	PROGRAM HscReport
C =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
C |                                                                 |
C | Program:     HscReport                                          |
C | Author:      Elie May                                           |
C | Objective:   Read log files from SET HOST/HSC/OUTPUT=HSCn.DAT   |
C |              and map out the HSC configuration                  |
C |                                                                 |
C =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
          INCLUDE 'HSC.INC'                   ! Global data declarations
          CALL Initialize                     ! Perform system initialization
          IHsc = 0                            ! Set current number of HSC's
C                                             ! to zero
          REPEAT UNTIL(Open_Error)            ! Proceed until no more files
            IHsc = IHsc + 1                   ! Increment number of HSC's
            CALL OpenHSC_File(Ihsc)           ! Try to open next HSC file
            WHEN( .NOT. Open_Error )          ! If successful
              CALL ReadHSC(Ihsc)              ! Read and sift the data
              CALL CloseHSC_File              ! Close file when done
            FIN                               !
            ELSE                              ! Otherwise
              IHsc = IHsc - 1                 ! correct for over increment
            FIN                               ! and we are done with data
          FIN                                 ! acquisition
          CALL Sort_Disks                     ! Sort the disk information
          CALL Generate_Report(Ihsc)          ! Prepare a report
          CALL Exit                           ! Exit
        END

        SUBROUTINE CloseHSC_File              ! Close Hsc File subroutine
          INCLUDE 'HSC.INC'                   ! Global data declarations
            CLOSE (Unit = 1)                  ! Close HSC data 
          RETURN
        END

        SUBROUTINE Generate_Report(NHscs)     ! Report Generator
          INCLUDE 'HSC.INC'                   ! Global data declarations
          CHARACTER*1 FormFeed                ! Declare form feed
          FormFeed=CHAR(12)                   ! Define form feed
          DO (Ihsc = 1 , NHscs)               ! For each HSC
            WRITE(Lu,555)FormFeed             ! Start on new page
555         FORMAT(1x,A1)                     ! Issue Title and basic info
            WRITE(Lu,*)' HSC CONFIGURATION REPORT ',HscName(Ihsc)
            WRITE(Lu,*)' '
            WRITE(Lu,*)' Booted:      ',HscBootTime(Ihsc)
            WRITE(Lu,*)' Up Time:     ',HscUpTime(Ihsc)
            WRITE(Lu,*)' HSC Panel:   ',HscFrontPanel(Ihsc)           
            WRITE(Lu,*)' HSC Type:    ',HscType(Ihsc)                 
            WRITE(Lu,*)' HSC Version: ',HscVersion(Ihsc)                 
            WRITE(Lu,*)' Disk Alloc. Class: ',HscAllocationClass(Ihsc,Disk) 
            WRITE(Lu,*)' Tape Alloc. Class: ',HscAllocationClass(Ihsc,Tape) 
            WRITE(Lu,787)                     ! Print top of box
            WRITE(Lu,782)(k-1,k=1,4)          ! Print column headers
782         FORMAT(1x,'|Req.|',4(' Port ',I1,13x,'|'))
            WRITE(Lu,787)                     ! Print separator line
C                                             ! For each requestor of HSC
            DO (Irequest = 1, HscRequestors(Ihsc) )
C                                             ! Print unit number on each port
                WRITE(Lu,788)(HscUnit(Ihsc,IRequest,Iport),Iport=1,4)
C                                             ! Print disk/device type
                WRITE(Lu,789)Irequest,(HscDevice(Ihsc,IRequest,Iport)
     1                ,Iport=1,4)
C                                             ! Format for device info
789             FORMAT(1x,'|',i3,4(' | ',A),' |')
C                                             ! Format for unit info
788             FORMAT(1x,'|',3X,4(' | ',A),' |')
                WRITE(Lu,787)                 ! Print bottom of box
787             FORMAT(1x,90('_'))
            FIN
          FIN
C                                             ! Prepare to print info
C                                             ! from unit number back to HSCs
          WRITE(Lu,555)FormFeed               ! New page
          WRITE(Lu,333)                       ! Top of box
333       FORMAT(
     1    ' -------------------------------------------------------------',
     2    '----------------------')
          WRITE(lu,334)                       ! Print column headers
334       FORMAT(
     1    ' | No.  | DISK   |  HSC    | Req | Port | HSC   | Req | Port |'
     2    ,' Type | Serial No    |')
          WRITE(Lu,333)                       ! Separator line
          DO (Idisk = 1 , NumDisks)           ! For each disk found
C                                             ! Test if connect to 1 or 2 HSCs
            WHEN(DiskInfo(PortBHsc,Idisk).EQ.0)
C                                             ! If one only then.
C                                             ! Note we are not certain whether
C                                             ! it is A or B.  Corrections
C                                             ! Must be done manually
C                                             ! Output info to report
              WRITE(Lu,335)Idisk,DiskInfo(Unit,Idisk),
     1          HSCName(DiskInfo(PortAHsc,Idisk)),
     2          DiskInfo(PortAReq,Idisk),                            
     3          DiskInfo(PortAPort,Idisk),DiskType(Idisk)
335         FORMAT
     1      (' | 'i4,' | ',i6,' | ',A6,' | ',i3,' | ',i4 ,
     2       ' |        |     |      | ',A4,' |              |')
            FIN
            ELSE                              ! If connected to 2 HSC's
C                                             ! Generate report accordingly
              WRITE(Lu,336)Idisk,DiskInfo(Unit,Idisk),
     1          HSCName(DiskInfo(PortAHsc,Idisk)),
     2          DiskInfo(PortAReq,Idisk),                            
     3          DiskInfo(PortAPort,Idisk),
     1          HSCName(DiskInfo(PortBHsc,Idisk)),
     2          DiskInfo(PortBReq,Idisk),                            
     3          DiskInfo(PortBPort,Idisk),DiskType(Idisk)
336         FORMAT
     1      (' | ',i4,' | ',i6,2(' | ',A6,' | ',i3,' | ',i4), ' | ',
     2       A4,' |              |')
            FIN
          FIN
          WRITE(Lu,333)                      ! Bottom line of report box
          CLOSE (Unit = Lu)                  ! Close report file
          RETURN                             ! return
        END

        SUBROUTINE Initialize                ! Initialize all system values
          INCLUDE 'HSC.INC'                  ! Global data definition
          DO (Ihsc = 1 , MaxHsc)             ! For the maximum number of HSC's
C                                            ! Clear all variables
            HscRequestors(Ihsc)            = 0 ! number of requestors
C                                            ! Name of HSC
	    HscName(MaxHsc)               = '      '
C                                            ! Boot time
            HscBootTime(Ihsc)             = '                   '
C                                            ! Up time
            HscUpTime(Ihsc)               = '           '
C                                            ! Front panel status
            HscFrontPanel(Ihsc)           = '       '
C                                            ! HSC software version
            HscVersion(Ihsc)              = '      '
C                                            ! HSC Type
	    HscType(Ihsc)                 = '     '
C                                            ! Allocation class for disk tape
	    HscAllocationClass(Ihsc,Disk) = '   ' ! for disk 
	    HscAllocationClass(Ihsc,Tape) = '   ' ! for disk 
C                                            ! Clear all requestor/port info
            DO (Irequest = 1, MaxRequestor)
              DO (Iport = 1 , MaxPort)
                HscDevice(Ihsc,IRequest,Iport)='                  '
                HscUnit(Ihsc,IRequest,Iport) = '                  '
              FIN
            FIN
          FIN
          NumDisks = 0                       ! No disks yet
          Lu = 2                             ! Define logical unit for report
C                                            ! and open file
          OPEN(Unit=Lu,File='HSC_CONFIG.RPT',Status='NEW')
          RETURN                             ! return
        END

        SUBROUTINE OpenHSC_File(Ihsc)        ! Open HSC data files
          INCLUDE 'HSC.INC'                  ! Global data definition
          CHARACTER*20 FileName              ! Filename to be built
                                             ! Convert number to Ascii digit
            Filename = 'HSC'//CHar(48+Ihsc)//'.LOG'
            Open_Error = .FALSE.             ! Preset logical variable
            OPEN(Unit=1,File=Filename,Status='OLD',Err=100)
            Open_Error = .NOT. Open_Error    ! Use double inversion technique
100         Open_Error = .NOT. Open_Error    ! For strict linear programming
          RETURN                             ! Return
        END

        SUBROUTINE ReadHSC(Ihsc)             ! Read HSC data
          INCLUDE 'HSC.INC'                  ! Global data definition
          CHARACTER*132    Line              ! Declare line buffer
          CHARACTER*18     SaveUnit          ! Save unit number
          CHARACTER*1      Space,Tab         ! Character variables
          INTEGER          Nchars            ! Number of characters
          INTEGER          Counter           ! Declare counter
          INTEGER          State             ! State transition control var
          LOGICAL          Done              ! Declare done flag and others
          LOGICAL          Found,Numeric,DataOkay,Finished
            Space   = ' '                    ! Set space
            Tab     = CHAR(9)                ! Set tab
            Counter = 0                      ! Initialize counter
            State   = 1                      ! Set to initial state
            Done    = .FALSE.                ! Initialize flag
            REPEAT UNTIL (Done)              ! Repeat until done
C                                            ! Read the line from HSC data 
              READ(1,100,Err=300,END=300)Nchars,Line(1:Nchars)
100           FORMAT(q,A)                    ! Format for reading
              Done = .NOT. Done              ! Double inversion flag technique
300           Done = .NOT. Done              ! For strict linear programming
              Counter = Counter + 1          ! Bump the counter
              IF(.NOT. Done)                 ! If we have data
                PROCESS-THE-LINE             ! Process it
              FIN                            ! End of If
            FIN                              ! End of repeat loop
          RETURN                             ! Return

          TO PROCESS-THE-LINE                ! Line processing
            SELECT (State)                   ! Go to appropriate state service
              (1)                            ! Look for boot info 
                  iboot = INDEX(Line,'Boot:')! Look for boot

                  IF(Iboot.NE.0)             ! yes
                    HscBootTime(Ihsc)=Line(Iboot+6:iboot+26)
                    Iup = INDEX(Line,'Up:')  ! up time
                    IF(Iup.NE.0)HscUpTime(Ihsc)=Line(Iup+4:Nchars)
                    State = 2                ! Next state
                  FIN
              FIN
              (2)                            ! Look for name and version
                  Iver = INDEX(Line,'Version:')
                  IF(Iver .NE. 0)            ! Found?
                    HSCVersion(Ihsc) = Line(Iver+9:Iver+12)
                    Iname=INDEX(Line,'Name:')! get Hsc name
                    IF(Iname.NE.0)
                      HscName(Ihsc)=Line(Iname+6:Nchars)
                    FIN
                    State = 3                ! move to next state
                  FIN
              FIN
              (3)                            ! Look for front panel state
                Ipanel = INDEX(Line,'Front Panel:')
                IF(Ipanel .LT. Nchars)
                  HscFrontPanel(Ihsc) = Line(Ipanel+14:Ipanel+20)
                  State = 4                  ! Next state
                  Itype = INDEX(Line,'HSC Type:')
                  IF(Itype.NE.0)HSCType(Ihsc)=Line(Itype+10:Nchars)
                FIN
              FIN
              (4)                            ! Get allocation class
                Iclass = INDEX(Line,'Disk Allocation Class:')
                IF(Iclass.NE.0)              ! got it
                  HSCAllocationClass(Ihsc,Disk)='$'//
     1                       Line(Iclass+26:Iclass+26)//'$'
                  State = 5                  ! Next state
                  Iclass=INDEX(Line,'Tape Allocation Class:')
                  IF(Iclass.NE.0)            ! got it
                    HSCAllocationClass(Ihsc,Tape)='$'//
     1                       Line(Iclass+26:Iclass+26)//'$'
                  FIN                  
                FIN
              FIN
              (5)                            ! Look for line before disks
                Iunit = INDEX(Line,'Unit')   ! and tapes
                IF(Iunit.NE.0)               ! got it
                  State = 6                  ! got to data acquisition
                FIN
              FIN
              (6)                            ! Look for data
                PARSE-THE-LINE               ! get information from line
                WHEN (DataOkay)              ! everything okay
                  IF(Irequest.GT.HSCRequestors(Ihsc))
                    HSCRequestors(Ihsc) = Irequest!remember highest requestor
                  FIN
                  HscDevice(IHsc,Irequest,Iport+1)=Line(Istart:Iend) 
                  IF(Line(Istart:Istart+1).EQ.'RA')
C                                            ! Register all disks
                    CALL Disk_Register(IUnit,IHsc,Irequest,Iport)
                  FIN
                  WHEN(HscUnit(IHsc,Irequest,Iport+1)(1:5).EQ.'     ')
                    HscUnit(IHsc,Irequest,Iport+1)=SaveUnit//
     1                     '               '
                  FIN
                  ELSE
                    HscUnit(IHsc,Irequest,Iport+1)=
     1	               HscUnit(IHsc,Irequest,Iport+1)(1:5)//Line(1:5)//
     2                     '          '
                  FIN                  
                FIN
                ELSE
                  IF(.NOT.Found)             ! Empty line
                    State = 5                ! look for next disk/tape grp
                  FIN
                FIN
              FIN
            FIN
          FIN
          TO PARSE-THE-LINE                  ! get information from line
            DataOkay = .FALSE.               ! Default
            Istart   = 1                     ! build unit number
            LOOK-FOR-NEXT-ITEM               !
            IF(Found.AND.Numeric)            !
              SaveUnit = Line(Istart:Iend)//'                  '
              BUILD-THE-NUMBER      
              Iunit = Number                 ! remember disk unit number
              Istart=Iend + 1                ! advance to next field
              LOOK-FOR-NEXT-ITEM
              IF(Found.AND.Numeric)          ! look for requestor
                BUILD-THE-NUMBER      
                Irequest = Number            ! Init requestor
                Istart = Iend + 1            ! next field
                LOOK-FOR-NEXT-ITEM
                IF(Found.AND.Numeric)        ! look for port
                  BUILD-THE-NUMBER           ! build the number
                  Iport    = Number
                  Istart = Iend + 1
                  LOOK-FOR-NEXT-ITEM         ! should be device type
                  IF(Found.AND. .NOT. Numeric)! if we made it all okay
                    DataOkay = .TRUE.
                  FIN
                FIN
              FIN
            FIN
          FIN

          TO LOOK-FOR-NEXT-ITEM              ! should be device type
            Found = .FALSE.                  ! Default
            WHILE(Istart.LE.Nchars.AND..NOT.Found)  !
              WHEN(Line(Istart:Istart).EQ.Space.OR.Line(Istart:Istart).EQ.TAB)
                Istart = Istart + 1
              FIN
              ELSE
                Found = .TRUE.               ! got something
                Iend = Istart - 1            ! look for data end from
                                             ! 1st character too
                Numeric = .TRUE.             ! Default
                Finished = .FALSE.           ! Init loop
                WHILE(.NOT.Finished)         !
                  WHEN(Iend.LT.Nchars)       !
                    SELECT (Line(Iend+1:Iend+1))  !
                      (Space)Finished = .TRUE.! loop complete
                      (Tab)  Finished = .TRUE.! loop complete
                      (OTHERWISE)
                        Iend = Iend + 1      ! move end pointer
                        IF(Line(Iend:Iend).LT.'0')Numeric=.FALSE.
                        IF(Line(Iend:Iend).GT.'9')Numeric=.FALSE.
                      FIN
                    FIN
                  FIN
                  ELSE
                    Finished = .TRUE.
                    IF(Line(Iend:Iend).LT.'0')Numeric=.FALSE.
                    IF(Line(Iend:Iend).GT.'9')Numeric=.FALSE.
                  FIN
                FIN
              FIN
            FIN
          FIN

          TO BUILD-THE-NUMBER 
            Number = 0                       ! init build area
            Limit = Iend                     ! set the limit
            IF(Limit.GT.Nchars)Limit = Nchars! protection
            Ipt = Istart                     ! set index
            WHILE(Ipt.LE.Limit.AND.Number.GE.0)! traverse data until done/err
              CONDITIONAL
                (Line(Ipt:Ipt).EQ.' ')       ! Skip spaces
                FIN
                (Line(Ipt:Ipt).GE.'0'.AND.Line(Ipt:Ipt).LE.'9') ! Numeric
                  Number = Number * 10 + Ichar (Line(Ipt:Ipt))-Ichar('0')
                FIN
                (OTHERWISE)
                  Number = -1                ! error illegal character
                FIN
              FIN
              Ipt = Ipt + 1                  ! next character
            FIN
          FIN
        END

        SUBROUTINE Disk_Register(IUnit,IHsc,Irequest,Iport)
          INCLUDE 'HSC.INC'                  ! Global data definition
            LOGICAL Found                    ! Declare flag
            Idisk = 1                        ! Initialize disk index
            Found = .FALSE.                  ! initialize found flag
C                                            ! and look if we already know
C                                            ! this disk
            WHILE(Idisk.LE.NumDisks.AND. .NOT. Found)
              WHEN(DiskInfo(Unit,Idisk).EQ.Iunit)Found = .TRUE.
              ELSE Idisk = Idisk + 1         ! if not found bump counter
            FIN
            WHEN (Found)                     ! if found store data in B 
C                                            ! channel area  (2nd port)
              DiskInfo(Unit,Idisk)      = Iunit
              DiskInfo(PortBHsc,Idisk)  = IHSC
              DiskInfo(PortBReq,Idisk)  = Irequest
              DiskInfo(PortBPort,Idisk) = Iport
            FIN
            ELSE                             ! New disk to us save info
              NumDisks = NumDisks + 1        ! add new disk
              DiskInfo(Unit,NumDisks)      = Iunit
              DiskInfo(PortAHsc,NumDisks)  = IHSC
              DiskInfo(PortAReq,NumDisks)  = Irequest
              DiskInfo(PortAPort,NumDisks) = Iport
              DiskType(NumDisks)=HscDevice(Ihsc,Irequest,Iport+1)
            FIN
          RETURN
        END

        SUBROUTINE Sort_Disks               ! Sort disks
          INCLUDE 'HSC.INC'                 ! Global data definition
          CHARACTER*4   Ctemp               ! Temporary area for switching
          LOGICAL Switch                    ! Switch flag
            Switch = .TRUE.                 ! Initialize switch flag
            REPEAT UNTIL (.NOT. Switch)     ! Bubble sort
              Switch = .FALSE.              ! no switches yet
              DO (idisk=1,NumDisks-1)       ! Loop through disks
                IF(DiskInfo(Unit,Idisk).GT.DiskInfo(Unit,Idisk+1)) ! must switch
                  Switch = .TRUE.           ! Set switch flag
                  DO (i=1,7)                ! Swap all disk information
                    Itemp               = DiskInfo(i,idisk)
                    DiskInfo(i,idisk)   = DiskInfo(i,Idisk+1)
                    DiskInfo(i,Idisk+1) = Itemp
                  FIN
                  Ctemp                 = DiskType(idisk)
                  DiskType(Idisk)       = DiskType(Idisk+1)
                  DiskType(Idisk+1)     = Ctemp
                FIN
              FIN
            FIN
          RETURN
        END
