! program to look for Illicit copies of a named file (e.g pacman.mob)
! merged with VFILES by Martin (MDP) April '84.

%constant %integer Date Flag = 2_1000 0000 0000 0000 0000 0000 0000 0000,
                   Info Flag = 2_0100 0000 0000 0000 0000 0000 0000 0000,
                   Perm Flag = 2_0010 0000 0000 0000 0000 0000 0000 0000,
                   Size Flag = 2_0001 0000 0000 0000 0000 0000 0000 0000,
                   Short Flag= 2_0000 1000 0000 0000 0000 0000 0000 0000,
                   Prot Flag = 2_0000 0100 0000 0000 0000 0000 0000 0000,
                   Today Flag= 2_0000 0010 0000 0000 0000 0000 0000 0000,
                   Yest Flag = 2_0000 0001 0000 0000 0000 0000 0000 0000

%constant %integer Left  = 4,
                   Right = 5,
                   False = 0,
                   True  = 1

%own %string (255) Wild File = ""
%own %integer      Flags = 0

%const %string (3) %array Days (1 : 12) = %c
   "31/", "28/", "31/", "30/", "31/", "30/",
   "31/", "31/", "30/", "31/", "30/", "31/"

%const %string (2) %array Months (1 : 12) = %c
   "01",  "02",  "03",  "04",  "05",  "06",
   "07",  "08",  "09",  "10",  "11",  "12"

!%include "Useful:Whodat.Inc"
%const %integer Min FS Users = 1,
                Max FS Users = 270

%include "INC:UTIL.IMP"
%include "INC:FS.IMP"
%externalstring(255)%fnspec FINFO(%string(255)directory,%integer number)
%include "Useful:LWildD.Inc"
%include "inc:fsutil.imp"

%begin
   %record (Dir Fm) %array File Store (1 : 101)
   %integer Number of Files = 0
   %string (255) A, B, Directory, Node
   %string (31) Sys Date, Yesterday, Temps
   %integer Stop Tail = False, Count = 0, Index, Dir Count = 0, X
   %integer Tot Used = 0, Node Flag = 0
   %integer Old Port, Old Uno, Users Port, FStore, EthErr = 0

   %routine Beautify (%string (*) %name S, %integer I)
      %byte %integer %name J
      %byte %integer Len = Byte Integer (Addr (S))
   
      %while I <= Len %cycle
        J == Char No (S, I)
        J = J ! ' '
        I = I + 1
      %repeat
   %end
      
   %routine Vax Format (%string (80) Directory)
      %record %format File Fm (%string (13) File, Ext, 
                               %string (16) Date,
                               %string (16) Size,
                               %string (16) Perm,
                               %integer Left, Right)

      %record (File Fm) %array Files (1:120)
      %integer Next Record = 1
      %record (Dir Fm) %name This File

      %string (255) Res String, Head String, Res, Last File = ""
      %string (15) File, FExt
      %string (15) F Date, F Size, F Perm, F Dir

      %integer Had One = 0, Number of Extensions = 0
      %integer File Pointer = 0, Header = 0, I, Len
      %integer Nl Flag = 0, Index, Sym, Temp
   
      %routine Add Totals (%string (*) %name Str)
         %string (255) A, B

         %if Str -> A .("("). B %start; %finish
         Tot Used  = Tot Used  + StoI (A)
      %end

      %routine Print Record (%integer Which)
      
         %record (File Fm) %name Ptr
      
         Ptr == Files (Which)
      
         Print Record (Ptr_Left) %if Ptr_Left > 0
      
         %if Flags & (\(Today Flag ! Yest Flag)) = 0 %start
            %if Ptr_File # Last File %start
      
               %if Had one # 0 %start
                  New Line
                  Number of Extensions = 0
               %finish
      
               Nl Flag = 0
               Had One = 1
      
               Last File = Ptr_File
               Print String (Last File)
               Spaces (14 - Length (Last File))
            %else
               %if nl flag = 1 %start
                  New line
                  spaces (14)
                  nl flag = 0
               %finish
            %finish
      
            %if Ptr_Ext # "" %start
               Print String (Ptr_Ext)
               Spaces (10 - Length (Ptr_Ext))
            %finish %else Print String ("_         ")
      
            Number of Extensions = Number of Extensions + 1
      
            nl flag = 1 %if Number of Extensions = 6
         %else
            %if Ptr_File # Last File %start
               Last File = Ptr_File
               Print String (Last File)
               Spaces (14 - Length (Last File))
            %finish %else Spaces (14)
      
            %if Ptr_Ext # "" %start
               Print String (Ptr_Ext)
               Spaces (10 - Length (Ptr_Ext))
            %finish %else Print String ("_         ")
      
            %if Flags & Size Flag # 0 %start
               Spaces (10 - Length (Ptr_Size))
               Print String (Ptr_Size)
               Add Totals  (Ptr_Size)
            %finish

            %if Flags & Perm Flag # 0 %start
               Spaces (5 - Length (Ptr_Perm))
               Print String (Ptr_Perm)
            %finish

            %if Flags & Date Flag # 0 %start
               Spaces (20 - Length (Ptr_Date))
               Print String (Ptr_Date)
            %finish

            New Line
         %finish

         Print Record (Ptr_Right) %if Ptr_Right > 0
      %end

      %routine Add Leaf (%integer Where, Side)

         %record (File Fm) %name Ptr

         Ptr == Files (Next Record)

         %if Side = Left %then Files (Where)_Left  = Next Record %c
                         %else Files (Where)_Right = Next Record

         Ptr_File  = File
         Ptr_Ext   = FExt

         %if Flags & (\(Today Flag ! Yest Flag)) # 0 %start
            Ptr_Perm  = F Perm
            Ptr_Size  = F Size
            Ptr_Date  = F Date
         %finish

         Ptr_Left  = 0
         Ptr_Right = 0
         Next Record = Next Record + 1
      %end

      %routine Insert (%integer Root)
         %record (File Fm) %name Ptr
      
         Ptr == Files (Root)

         %if Next Record = 1 %start
            Ptr_File  = File
            Ptr_Ext   = FExt

            %if Flags & (\(Today Flag ! Yest Flag)) # 0 %start
               Ptr_Perm = F Perm
               Ptr_Size = F Size
               Ptr_Date = F Date
            %finish

            Ptr_Left  = 0
            Ptr_Right = 0
            Next Record = 2
         %else
             %if Ptr_File = File %start
               %if Ptr_Ext > FExt %start
                  %if Ptr_Left > 0 %then Insert (Ptr_Left) %c
                                   %else Add Leaf (Root, Left)
               %else
                  %if Ptr_Right > 0 %then Insert (Ptr_Right) %c
                                    %else Add Leaf (Root, Right)
               %finish
            %else %if Ptr_File > File
               %if Ptr_Left > 0 %then Insert (Ptr_Left) %c
                                %else Add Leaf (Root, Left)
            %else
               %if Ptr_Right > 0 %then Insert (Ptr_Right) %c
                                 %else Add Leaf (Root, Right)
            %finish
         %finish
      %end

      %on 0,1,2,3,4,5,6,7,8,9 %start
         %return
      %finish

      Files (1)_Left  = -1
      Files (1)_Right = -1
      Head String = Finfo (Directory, 0)
      Header = Header + 1 %while Header <= Byte Integer (Addr (Head String)) %and %c
                                 Charno (Head String, Header) # ')'
      Head String = " in directory ".Node.Sub String (Head String, 1, Header)
   
      Index = 1
      %while Index <= Number of Files %cycle
         This File == File Store (Index)
         %if Flags # 0 %start
            Res = Finfo (Directory, This File_Index)
            Temp = 14
            Temp = Temp + 1 %while Charno (Res, Temp) = ' '
            Res = Sub String (Res, Temp, Length (Res))

            %if Flags & Today Flag # 0 %or Flags & Yest Flag # 0 %start
               Temps = SubString (Res, 7, 14)

               %if Flags & Today Flag # 0 %and Flags & Yest Flag = 0 %start
                  %exit %if Temps # Sys Date
               %else %if Flags & Yest Flag # 0 %and Flags & Today Flag = 0
                  Index = Index + 1 %and %continue %if Sys Date = Temps
                  %exit %if Temps # Yesterday
               %else %if Flags & Yest Flag # 0 %and Flags & Today Flag # 0
                  %exit %if Temps # Sys Date %and Temps # Yesterday
               %finish
            %finish

            F Perm = Sub String (Res, 1, 3)
            F Date = Sub String (Res, 7, 21)
            F Size = Sub String (Res, 24, Length (Res))
         %finish

         %if This File_File -> File .("."). Fext %start
            Fext = "." . Fext
            Beautify (Fext, 3)
         %else
            File = This File_File
            Fext = ""
         %finish

         Beautify (File, 2)
         Insert (1)
         Index = Index + 1
      %repeat

      Number of Files = Next Record - 1
      %if Number of Files # 0 %start
         Print Record (1)
         New Line %if Flags & (\(Today Flag ! Yest Flag)) = 0
      %finish

      %if Number of Files # 0 %or Stop Tail = False %start
         Res String = I To S (Number of Files, 0) . " file"
         Res String = Res String . "s" %if Number of Files # 1

         %if Flags & Size Flag # 0 %start
            Res String = Res String . " (" . ItoS (Tot Used, 0). " block"
            Res String = Res String . "s" %if Tot Used # 1
            Res String = Res String . ")"
         %finish

         Res String = Res String . " matched with '".Wild File."'" %c
            %if Wild File # "**"
         Res String = Res String . " modified today" %c
            %if Flags & Today Flag # 0 %and Flags & Yest Flag = 0
         Res String = Res String . " modified yesterday" %c
            %if Flags & Yest Flag # 0 %and Flags & Today Flag = 0
         Res String = Res String . " modified in the last 2 days" %c
            %if Flags & Yest Flag # 0 %and Flags & Today Flag # 0
         Res String = Res String . Head String
         Format (Res String)
         New Line
         Tot Used = 0
      %finish
   %end

   %routine Short Format (%string (80) Directory)
      %string (80) Res
      %integer Counter, Index

      %if Number of Files # 0 %start
         Directory = Current Directory %if Directory = ""

         Print String (Node.Directory.": ")
         Write (Number of files, 0)
         Print String (" file")
         Print Symbol ('s') %if Number of Files # 1
         Print String (" found.")
         New Line
         Count = Count + Number of Files
         Counter = 0

         %for Index = 1, 1, Number of Files %cycle
            Counter = Counter + 1
            Res = File Store (Index)_File
            Beautify (Res, 2)
            Print String (Res)
            Spaces (13 - Length (Res))

            %if Counter = 6 %start
               New Line
               Counter = 0
            %finish
         %repeat
         New Line %if Counter # 0
         New Line
      %finish
   %end

   %routine Print Directory (%string (80) Directory)

      %if Flags & Short Flag # 0 %then Short Format (Directory) %c
                                 %else Vax   Format (Directory)
   %end

   %routine Print Details

      Print String ("A total of ")
      Announce ("file", Count)

      %if Wild File -> A .("*"). B %or Wild File -> A .("%"). B %start
         Print String (" matching '".Wild File."'")
      %else
         Print String (" called '".Wild File."'")
      %finish

      %if Count # 1 %then Print String (" were") %else %c
                          Print String (" was")
      Print String (" found in ")
      Write (Dir Count,0)
      %if Dir Count # 1 %then Print String (" directories") %c
                        %else Print String (" directory")
      Print string (" on ".Node) %if Node # ""
      New Line
   %end

   %predicate Exists (%string (15) Who, File Name)
      %on 9 %start
         %false
      %finish

      Open Input (3, Who.":".File Name)
      Select Input (3)
      %true
   %end

   %routine Print Directories Only
      %string (80) Res
      %integer Index, Qwaszx

      %for Index = Min FS Users, 1, Max FS Users %cycle
         %if Matches (FS Users (Index), Directory) %start
            %if Exists (Fs Users (Index), Wild File) %start
               Res = FS Users (Index)
               Count = Count + 1
               Print String (Res)
   
               %if Rem (Count, 10) = 0 %start
                  New Line
               %else
                  Space %for Qwaszx = Length (Res), 1, 7
               %finish
            %finish
            Dir Count = Dir Count + 1
         %finish
      %repeat
      New Line %if Rem (Count, 10) # 0
   %end

   %predicate gotack(%integer port)
   ! Wait for ACK and return TRUE.
   ! Return FALSE if fed up waiting.
   %integer bit,deadline
     bit = 1<<port
     deadline = cputime+15000
     %cycle
       %if ack&bit#0 %start
         %trueif nak&bit=0
         nak = nak!!bit
         %false
       %finish
     %repeatuntil cputime>deadline
     %false
   %end

   %predicate gotdtx(%integer port)
   ! Wait for DTX and TRUE.  FALSE when fed up
   %integer bit,deadline
     bit = 1<<port
     deadline = cputime+15000
     %cycle
       %trueif dtx&bit#0
     %repeatuntil cputime>deadline
     %false
   %end

   %routine connect(%integer port,node)
   ! Establish a connection between local port PORT
   ! and network server NODE providing facility 2 (Filestore)
   %string(127)reply
   %integer i
   %byte facility
   {printstring("Attempting to connect port "); phex2(port)
   {printstring(" to node "); phex2(node); newline
     facility = 2
     etheropen(port,node<<8)
     etherwrite(port,facility,1)
     %unless gotack(port) %start
       printstring("Node "); phex2(node)
       printstring(" not acknowledging connect request")
       etherclose(port)
       newline
       EthErr=1; %return
     %finish
     %unless gotdtx(port) %start
       printstring("Node "); phex2(node)
       printstring(" not responding to connect request")
       etherclose(port)
       newline
       EthErr=1; %return
     %finish
     length(reply) = etherread(port,charno(reply,1),127)
     i = charno(reply,length(reply))
     %unless i=nl %and length(reply)=2 %and charno(reply,1)>'0' %start
       printstring("Cannot connect to node "); phex2(node)
       printstring(": ".reply)
       etherclose(port)
       newline %unless i=nl
       EthErr=1; %return
     %finish
     i = charno(reply,1)-'0'
     etheropen(port,node<<8+i)
   {printstring("Local port "); phex2(port); printstring(" connected to node ")
   {phex2(node); printstring(" port "); phex2(i); newline
   %end

   %routine disconnect(%integer port)
   %byte eot = 12
     %onevent 15 %start
       %return
     %finish
   {printstring("Attempting to disconnect port "); phex2(port)
   {printstring(" from node "); phex2(FStore); newline
     etherwrite(port ,eot,1)
     %unless gotack(port) %start
       printstring("Cannot disconnect port "); phex2(port)
       printstring(" from node "); phex2(FStore)
       printstring(" - Nak")
       %return
     %finish
     etherclose(port)
   {printstring("Disconnected port "); phex2(port)
   {printstring(" from node "); phex2(FStore); newline
   %end

   %integer %fn FS Host
      %const %string (9) %array nodes (1 : 7) = %c
         "ALPHA", "WEE",
         "BRAVO", "BIG",
         "CHARLIE",
         "PORTABLE", "MINI"
      %const %integer %array addresses (1 : 7) = %c
         16_14, 16_14,
         16_15, 16_15,
         16_1b,
         16_3f, 16_3f
      %integer Index

      %for Index = 1, 1, 7 %cycle
         Node = Nodes (Index) . "::" %and %result = Addresses (Index) %c
            %if Substring (Nodes (Index), 1, Length (Node)) = Node
      %repeat

      Print String ("Unknown node '".Node."'")
      New Line
      Node = ""
      %result = RDTE
   %end

   Define Param ("Wildfile", Wild File, 0)
   Define Boolean Params ("Date,Info,Permission,Size,SHort,".%c
                          "PRotection,Today,Yesterday",
                          Flags,
                          0)

   Process Parameters (CLI Param)
   Flags = (Flags ! (Size Flag ! Perm Flag ! Date Flag)) & (\Info Flag) %c
      %if Flags & Info Flag # 0
   Flags = Flags ! Perm Flag & (\Prot Flag) %if Flags & Prot Flag # 0
   Sys Date = Date %if Flags & Today Flag # 0

   %if Flags & Yest Flag # 0 %start
      Sys Date = Date

      %if SubString (Sys Date, 1, 2) # "01" %start
         Yesterday = ItoS (Stoi (SubString (Sys Date, 1, 2)) - 1, 0)
         Yesterday = "0" . Yesterday %if Length (Yesterday) = 1
         Yesterday = Yesterday . Sub String (Sys Date, 3, 8)
      %else
         ! -- new month
         %if Substring (Sys Date, 4, 5) # "01" %start
            X = StoI (SubString (Sys Date, 4, 5)) - 1
            Yesterday = Days (X)
            Yesterday = Yesterday . Months (X) . Sub String (Sys Date, 6, 8)
         %else
            ! -- new year
            Yesterday = "31/12/" . ItoS (StoI (SubString (Sys Date, 7, 8))-1, 0)
         %finish
      %finish
   %finish

   Node = ""
   %if Wild File -> Node .("::"). Wild File %start; %finish
   %if Node # "" %start
      Node Flag = 1
      FStore = FS Host
      Old Uno  = User No
      User No  = 0
      Old Port = FS Port
      Users Port = 16
      Connect (Users Port, FStore)
      FS Port = Users Port
   %finish

   Directory = ""
   %if Wild File -> Directory .(":"). Wild File %start; %finish
   %if Wild File -> A .("."). B %start
      A = "*" %if A = ""
      Wild File = A .".". B
   %finish

   Wild File = "**" %if Wild File = ""
   Wild File = "*" %if Wild File = "-" %or Wild File = "_"

   %if Directory -> A .("*"). B %or Directory -> A .("%"). B %start
      ! -- Special Files, Wildcard Directory

      %if Wild File -> A .("*"). B %or Wild File -> A .("%"). B %start
         ! -- Wild card filespec also

         Stop Tail = True
         %for Index = Min FS Users, 1, Max FS Users %cycle
            %if Matches (FS Users (Index), Directory) %start
               New Line %if Number of Files # 0
               Load Wild Directory (File Store, Number of Files,
                                    FS Users (Index), Wildfile)
               Print Directory (FS Users (Index))
            %finish
         %repeat
      %else
         ! -- Normal file, only print matching directories

         Print Directories Only
         Print Details
      %finish
   %else
      ! -- Standard Files

      !! Wild File = Wild File . "*" %unless %c
      !!    Charno (Wild File, Length (Wild File)) = '*'
      Load Wild Directory (File Store, Number of Files, Directory, Wild File)
      Print Directory (Directory)
   %finish

   %if Node Flag # 0 %start
      Disconnect (Users Port) %if EthErr = 0

      FS Port = Old Port
      User No = Old Uno
   %finish
%end %of %program
