! Filestore Port killing program (posher AutoChop)
! MDP April'84

%begin

%include "managr:nsdefs.inc"
%include "Inc:Fs.IMP"
%include "Inc:Util.IMP"
%include "managr:ns.inc"

%own %string (31) Sys Time = "",
                  Sys Date = ""

%string (2) %fn Hex 2(%integer xx)

   %const %byte %array Hex Sym (0 : 15) = %c
      '0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
   %string (2) Frig = To String (Hex Sym ((Xx >> 4) & 15)) . %c
                      To String (Hex Sym (Xx & 15))

   %result = String (Addr (Frig))
%end

%routine Format(%string (255) Line)
   %string (80) This

   %cycle
      %if Length (Line) > 80 %start
         This = Sub String (Line, 1, 80)
         Line = Sub String (Line, 81, Length (Line))
      %else
         This = Line
         Line = ""
      %finish
      Print String (This)
      New Line %if Line # ""
   %repeat %until Line = ""
%end

%routine Announce(%string (80) What, %integer Count)

   Write (Count ,0)
   Space
   Print String (What)
   Print Symbol ('s') %if Count # 1
%end

%integer %fn Day Difference (%string (7) Lower, Upper)

   %string (2) Lo Hrs = Sub String (Lower, 1, 2),
               Lo Min = Sub String (Lower, 4, 5)
   %string (2) Hi Hrs = Sub String (Upper, 1, 2),
               Hi Min = Sub String (Upper, 4, 5)
   %integer Total

   %if Lo Hrs = Hi Hrs %start
      Total = StoI (Hi Min) - StoI (Lo Min)
   %else
      Total = 60 * (S to I (Hi Hrs) - S to I (Lo Hrs))
      Total = Total + (S to I (Hi Min) - S to I (Lo Min))
   %finish
   %result = Total
%end

%integer %fn Time Difference (%string (31) Time Rating)

   %string (15) Day
   %string (7)  Tim

   %if Time Rating -> Day .(" "). Tim %start; %finish
   Tim = Sub String (Tim, 2, Length (Tim)) %while Charno (Tim, 1) = ' '

   %if Sys Date = Day %start
      %result = Day Difference (Tim, Sys Time)
   %else
      %result = 24 * 60 - Day Difference (Sys Time, Tim)
   %finish
%end

%integer %fn Minimum Difference(%string (31) One, Two)

   %integer I One,
            I Two

   Sys Time = Time %if Sys Time = ""
   Sys Date = Date %if Sys Date = ""

   I One = Time Difference (One)
   I Two = Time Difference (Two)

   %result = I One %if I One < I Two
   %result = I Two
%end

%record %format User Fm (%string (6) User Name, Directory,
                         %string (21) Login Time,
                         %byte Uno, Pno, Flags, Location,
                         %short Difference)

%routine Get Unos From FS(%record (User Fm) %array %name Users (1 : *),
    %integer %name Number of Users,
    %integer %name Number of Internal Copies)   ;! -- for Users

   %record (User Fm) %name Element
   %string (19) User, Dir, Login
   %string (19) Read Time, Write Time
   %string (8) Today = Date
   %integer Id, Sym, Flag, Uno, Pno
   %integer nl flag = 0
   %integer tptr,tlen,taddr

   %routine Read Sym (%integer %name sym)

      %signal 9 %if tptr = taddr+tlen
      sym = byteinteger(tptr)
      tptr = tptr+1
   %end
         
   %routine Skip Symbol
      %integer sym

      read sym (sym)
   %end

   %integer %fn Hex Sym (%integer Sym)

      %result = Sym - '0' %if '0' <= Sym <= '9'
      %result = Sym - 'A' + 10
   %end

   %routine Read Rest of (%string (19) %name What)

      %integer Sym

      %cycle
         Read Sym (Sym)
         nl flag = 1 %and Sym = ' ' %if sym = nl
         %exit %if Sym = ' '
         What = What . To String (Sym)
      %repeat
   %end

   %routine Skip Spaces (%integer %name Sym)

      Sym = ' '
      Read Sym (Sym) %while Sym = ' '
   %end

   %routine Read Date (%string (*) %name Dat, %integer %name Sym)

      Dat = To String (Sym)
      Read Rest of (Dat)
      Dat = Dat ." "
      Skip Spaces (Sym)
      Dat = Dat . To String (Sym)
      Read Rest of (Dat)
   %end

   %on 9 %start
      -> End Load
   %finish

{ Print String ("In Get FS Unos..."); New Line
   Sys Time = Time
   Sys Date = Date

   Number of Users = 0
   Number of Internal Copies = 0
   Connect File ("$:UNOS",0,taddr,tlen)
{ Print String ("File connected at addr = "); PHex (taddr)
{ Print String (" to of len = "); PHex (TLen); New Line
   tptr = taddr
   
   Read Sym (Sym) %until Sym = Nl      ;! skip ANON

! 6  -2           pub     pub  ---login------  -----read-----  -----write----
   %cycle
      Flag = 0
      Skip Symbol                      ;! leading space

      ! -- Uno

      Read Sym (Sym)
      Read Sym (Uno)
      %if Sym # ' ' %then Uno = 10 * (Sym - '0') + (Uno - '0') %c
                    %else Uno = Uno - '0'

      ! -- 2 Spaces

      Skip Symbol
      Skip Symbol

      ! -- Port Number

      Read Sym (Sym)
      %if Sym = '-' %start
         Number of Internal Copies = Number of Internal Copies + 1
         Read Sym (Sym) %until Sym = Nl
         %continue
      %finish

      Read Sym (Pno)
      %if Sym # ' ' %then Pno = 10 * (Sym - '0') + (Pno - '0') %c
                    %else Pno = Pno - '0'

      ! -- 2 Spaces

      Skip Symbol
      Skip Symbol

      ! -- Terminal Address

      Read Sym (Sym)
      Read Sym (Id)
      Id = 16 * Hex Sym (Sym) + Hex Sym (Id)

      ! -- 3 Spaces

      Skip Symbol %for Sym = 1, 1, 3      ;! skip upto spaces before user name

      ! -- Username

      Skip Spaces (Sym)
      User = To String (Sym)
      Read Rest of (User)

      %if Charno (User, Length (User)) = '!' %start
         Flag = 1
         Length (User) = Length (User) - 1
      %finish

      Skip Spaces (Sym)
      Dir = To String (Sym)
      Read Rest of (Dir)

      Skip Spaces (Sym)
      Login = To String (Sym)
      Read Rest of (Login)
      Skip Spaces (Sym)
      %if Login # Today %then Login = Login . " " . To String (Sym) %c
                        %else Login = To String (Sym)
      Read Rest of (Login)

      Skip Spaces (Sym)
      Read Date (Read Time, Sym)

      Skip Spaces (Sym)
      Read Date (Write Time, Sym)
      %if nl flag = 0 %start
         Read Sym (Sym) %until Sym = Nl
      %finish

      Number of Users    =  Number of Users + 1
      Element            == Users (Number of Users)
      Element_Uno        =  Uno
      Element_Pno        =  Pno
      Element_User Name  =  User
{ Print String ("Read user '".User."'");New Line
      Element_Directory  =  Dir
      Element_Login Time =  Login
      %if 00<=id<=255 %then element_location=id %else %c
      Element_Location   =  255
      Element_Flags      =  Flag
      Element_Difference =  Minimum Difference (Read Time, Write Time)
   %repeat

End Load:
{ Print String ("Leaving Get FS Unos..."); New Line
   Sys Time = ""
   Sys Date = ""
%end

%constant %string (6) Free Location = "*Free*"

%constant %integer Vax Station 1 = 16_03,
                   Vax Station 2 = 16_72

%record %format Port Fm (%string (2) Local,
                         %integer Remote Id,
                         %string (2) Remote P,
                         %integer Difference)

%record (Port Fm) %array Ports (1:48)
%integer Number of Ports = 0
%record (User Fm) %array Users (1 : 48)
%integer Number of Users = 0

%byte %integer Local S  = L Dte,
               Local P  = L Sap,
               Remote S = R Dte,
               Remote P = R Sap,
               Host     = R Dte

%routine Chop
   %byte Four = 12

   Ether Write (FS Port, Four, 1)
   %cycle
   %repeat %until Ack&1 << FS Port # 0
%end

%routine Alias (%integer FS Station, FS Port No, APM Station, APM Port No)

   Ethc = 15
   T Wait
   Ethc = 7
   T Wait
   Ethd = APM Station
   T Wait
   Fsport = APM Port No
   Ether Open (FS Port, FS Station << 8 + FS Port No)
%end

%string (31) %fn Sleep State (%integer Minutes)
   %const %string (31) %array Comments (0:7) = %c
      "",             "beginning to yawn ",
      "drowsing ",    "dropping off ",
      "asleep ",      "snoring gently ",
      "fast asleep ", "dead to the world "

   Minutes = Minutes // 10
   Minutes = 0 %if Minutes < 0         ;! ???
   Minutes = 7 %if Minutes > 7
   %result = Comments (Minutes)
%end

%Routine Get Table From FS

   %string (80) Line
   %string (19) Read Time, Write Time
   %string (2) Loc P, Rem P, Temp I
   %integer Rem I
   %record (Port Fm) %name Port

   %integer %fn Hex Char (%integer Sym)

      %result = Sym - '0' %if '0' <= Sym <= '9'
      %result = Sym - 'A' + 10
   %end

   %on 9 %start
      -> End Load
   %finish

   Number of Ports = 0
   Open Input (1, "$:Ports")
   Select Input (1)

   %cycle
      Read Line (Line)

      Loc P = Sub String (Line, 2, 3)
      Temp I = Sub String (Line, 6, 7)
      Rem I = Hex Char (Charno (Temp I, 2))
      Rem I = 16 * Hex Char (Charno (Temp I, 1)) + Rem I %if Charno (Temp I, 1) # ' '
      Rem P = Sub String (Line, 9, 10)

      Read Time = Sub String (Line, 13, 26)
      Write Time = Sub String (Line, 29, 42)

      Number of Ports = Number of Ports + 1
      Port == Ports (Number of Ports)

      Port_Local      = Loc P
      Port_Remote Id  = Rem I
      Port_Remote P   = Rem P
      Port_Difference = 1{Minimum Difference (Read Time, Write Time)
   %repeat

End Load:
   Close Input
   Select Input (0)
%end

   %record (Port Fm) %name Port
   %record (User Fm) %name User
   %string (255) Temp Res, Res, Parm = CLI Param
   %string (7) Whos Using, S Pno
   %record (ns lfm) data
   %integer Number of Dead = 0
   %integer Pno, Uno, Len, Nic
   %integer P L, P R, Sym, i, j, xno

   Get Table From Fs
   Get Unos From Fs (Users, Number of Users, Nic)
   xno = open ns db

   %for Pno = 1,1, Number of Ports %cycle
      Port == Ports (Pno)
      Res = ""
      Res = Port_Local ." ".Hex2 (Port_Remote Id)." ".Port_Remote P." : "

      Whos using = Free Location

      %for Uno = 1, 1, Number of Users %cycle
         User == Users (Uno)
         %if User_Pno < 10 %then SPno = I To S (User_Pno, 1) %c
                           %else SPno = I To S (User_Pno, 0)

         %if Port_Local = S Pno %start
            Whos Using = User_User Name
            %exit
         %finish
      %repeat

      Whos Using = " " . Whos Using %while Length (Whos Using) < 6
      Res = Res . Whos Using . " " . Sleep State (Port_Difference)

      i = read ns db(xno, port_remote id!long, addr(data))
      %if i>=0 %start
         %if data_inon = 'I' %start
            res=res."   In "
         %elseif data_inon = 'O'
            res=res."   On "
         %elseif data_inon = 'A'
            res=res."   At "
         %finish

         res=res."the " %if data_room = 'T'

         %for j=31,-1,1 %cycle; %exit %if data_lname(j) > ' '; %repeat
         %for i=1,1,j %cycle; res=res.tostring(data_lname(i)); %repeat
         res=res."'s room" %if data_room = 'R'
      %else
        res=res."On a mythical machine "
      %finish

      Res = Res . " " %while Length (Res) < 74
      Res = Res . ":"
{      Print String (Res); newline
      Prompt (Res)
      Sym  = Test Symbol %until Sym = -1
      Read Symbol (Sym) %until Sym!' ' = 'n' %or Sym!' ' = 'y' %or Sym = Nl

      %if Sym ! ' ' = 'y' %start
         %if Whos Using # Free Location %start
            Prompt ("That terminal is occupied, Are you sure : ")
            P L  = Test Symbol %until P L = -1
            Read Symbol (Pl) %until Pl!' ' = 'n' %or Pl!' ' = 'y' %or Pl = Nl
         %else
            P L = 'y'
         %finish

         %if P L! ' ' = 'y' %start
            P L = S To I (Port_Local)
            P R = S To I (Port_Remote P)
            Alias (Host, P L, Port_Remote Id, P R)
            Chop
            Alias (Remote S, Remote P, Local S, Local P)
            Number of Dead = Number of Dead + 1
            Number of Users = Number of Users - 1 %if Whos Using # Free Location
         %finish
      %finish
       
      Read Symbol (Sym) %while Sym # Nl
   %repeat

   close ns db(xno)

   Announce ("port", Number of Ports)
   Print String (" allocated with ")
   Announce ("port", Number of Dead)
   Print String (" killed and ")
   Write (Number of Users, 0)
   Print String (" now left in use.")
   New Line
%end %of %program
