!Program to infer when a directory was last used by the most recent write date
!Parameter is directory name. Default = current directory.  Note it will fail
!to give the correct date unless the system password is quoted.
!J. Butler 11/85

%include "inc:ssi.imp"
%include "inc:fsutil.imp"
%begin
%string (255) %array users(0:1023)
%string (255) usr, param, outfile
%integer d, first, last, p

%recordformat FINFO FM( %c
%string(23)name,%string(9)date,time,%integer blocks,extents,
(%string(5)perms %or (%integer maxblocks, files, partno, dirno)))

%routine unpack finfo(%string(127)s,%record(finfo fm)%name r)
   !Differs from the standard one in that it'll unpack FINFO(0)
   !Get the string of information from FINFO and NINFO into a better form.
   !Note if length(s) > 60 it assumes we have a directory record and splits
   !it accordingly.

   %integer pos=1

   %routine scan
      !skip past leading spaces
      pos = pos+1 %while pos<=length(s) %and charno(s,pos)=' '
   %end

   %routine skip(%integer n)
      !Skip past n printing characters - Blow up if done at end of string.
      %integer i
      %for i = 1, 1, n %cycle
         scan
         pos = pos + 1
      %repeat
   %end


   %integerfn d
      !interpret (global) s as a decimal integer
      %integer n=0,k
      scan
      %cycle
         %result = n %if pos>length(s); pos = pos+1; k = charno(s,pos-1)-'0'
         %result = n %if k<0 %or k>9; n = n*10+k
      %repeat
   %end

   %routine w(%string(*)%name t,%integer max)
      !read s into t, ignoring leading spaces and stopping at max or the first
      !space
      %integer k
      scan; t = ""
      %cycle
         %returnif pos>length(s) %or max<=0
         k = charno(s,pos); pos = pos+1; max = max-1
         %returnif k=' '
         t = t.tostring(k)
      %repeat
   %end

   r = 0
   %if length(s) < 60 %start
      w(r_name,23); w(r_perms,5); w(r_date,9); w(r_time,9)
      r_blocks = d; r_extents = d
   %else
      w(r_name, 7); skip(1); r_partno = d; r_dirno = d; skip(2)
      w(r_time,5); skip(2); w(r_date, 8)
      skip(8); r_files = d; skip(8); r_extents = d; skip(7); r_blocks = d
      r_maxblocks = d
   %finish
%end

%string (255) %fn lastused(%string (255) directory)
   %record (finfo fm) r,d
   %string (255) last

   %on 3 %start 
      %result = "non-existant"
   %finish

   last= finfo(directory, 0)
   unpack finfo(last, d)

   last=finfo(directory,1)
   %if last = "" %start
      %result = "empty   " %if d_files=0
      %result = "unreadable"
   %finish

   unpack finfo(last, r)
   %result = r_date
%end

%ownbytearray buffer(0 : 511)
%ownbytename nextone
%ownbytename lastone

%routine do(%integer what, %string(31) param)
   %integer i
      i = fcommr(what << 8, param, buffer(0), 512)
      nextone == buffer(0)
      lastone == nextone[i]
%end

%integerfn next sym
   %integer ch
      %result = -1 %if nextone == lastone
      ch = nextone
      nextone == nextone[1]
      %result = ch
%end

%string(31)%fn next word
   %string(31) s
   %integer ch
      s = ""
      ch = next sym %until ch > ' '
      %cycle
         s = s . to string(ch)
         ch = next sym
      %repeat %until ch <= ' '
      %result = s
%end

%routine get users(%integer p, %integername total)
   %integer i
   total=0
   do('\', to string('0' + (p << 1)))
   %for i=1,1,64 %cycle
      users(total) = next word; total=total+1 %if users(total) # "---"
   %repeat
   do('\', to string('0' + (p << 1) + 1))
   %for i=1,1,64 %cycle
      users(total) = next word; total=total+1 %if users(total) # "---"
   %repeat
%end

%routine sort users(%integer from, to)
   %string(7) d
   %integer l, u
   %label up, fi, fo, do
      %return %if from >= to
      l = from;  u = to
      d = users(u)
      -> fi
up:   l = l + 1;  -> fo %if l = u
fi:   -> up %unless users(l) >= d
      users(u) = users(l)
do:   u = u - 1;  -> fo %if l = u
      -> do %unless users(u) <= d
      users(l) = users(u)
      -> up
fo:   users(u) = d
      sort users(from, l - 1)
      sort users(u + 1, to)
%end

%predicate using syspass
   %string (255) line, u
   %on 3,9 %start
      close input; selectinput(0); %false
   %finish

   u = current user."!"
   openinput(1, "$:unos"); selectinput(1)
   %cycle
      readline(line)
      %exit %if line -> (u)
   %repeat
   close input; selectinput(0); %true
%end

last=1
set terminal mode(8)
param = cli param
usr = param %and outfile = "" %unless param -> usr.("/").outfile
users(0)=usr
%if cliparam="" %then users(0)=current directory 
%unless (using syspass %or users(0)=current user) %start
   printline("*** Syspass not quoted.  Last use is calculated on latest    ***")
   printline("*** write date of ACCESSIBLE files so is probably inaccurate ***")
%finish
newline
%if outfile# "" %start; open output(2, outfile); selectoutput(2); %finish
%if cliparam="*" %start
   %for p=0,1,7 %cycle
      newline
      printstring("Partition ");  write(p, 0)
      printstring(" at ");  printstring(time)
      printstring(" on ");  printstring(date)
      newline
      get users(p, last)
      sort users(0, last-1)
      %for d=0, 1, last-1 %cycle
         printstring(users(d)); spaces(7-length(users(d)))
         users(d) = lastused(users(d))
         printstring(users(d))
         %if d&3=3 %then newline %else spaces(12-length(users(d)))
      %repeat
      newline
   %repeat
%finish

%for d=0, 1, last-1 %cycle
   printstring(users(d)); space
   users(d) = lastused(users(d))
   %if '0'<=charno(users(d),1)<='9' %then printline("last used ".users(d)) %else %c
   printline(users(d))
%repeat
%endofprogram
