	SUBROUTINE AGN_REC ()
C	###############################################################
C	# (C) Copyright 1985 Auto-trol Technology Corporation         #
C	#                                                             #
C	# This program is the sole property of Auto-trol Technology   #
C	# Corporation and is considered a trade secret and/or a       #
C	# proprietary product of Auto-trol Technology Corporation.    #
C	# Use or disclosure of this program by other than Auto-trol   #
C	# Technology Corporation and its assigned licensees and       #
C	# customers is strictly forbidden by law.                     #
C	#                                                             #
C	# Use, duplication or disclosure by the Government is subject #
C	# to restrictions as set forth in subdivision (b)(3)(ii) of   #
C	# the Rights in Technical Data and Computer Software clause   #
C	# at 252.227.7013.                                            #
C	###############################################################
C
C      /BEGIN MODULE HEADER/        		/STANDARD MODULE HEADER/
C
C       NAME -- AGN_REC
C
C       PURPOSE -- 
C 
C	  Subroutines to manipulate records in REC database
C
C       INTERNAL DESCRIPTION AND DESIGN CONSIDERATIONS --
C
C	  Routines collected here attempt to isolate the the rest of 
C	  the code from dependencies on the file in use (originally used
C	  VMSPARAMS.DAT, currently MODPARAMS.DAT)
C	  Most record references are based on RECORD INDEX (IND), assuming
C	  IND has been returned to caller by AGN_REC_LOC.
C
C       NOTES --
C	  This module HIDES all the dependencies on file in use.
C
C       HISTORY --
C         MM/DD/YY,SDRC,functional spec number,initials,comments
C	  10/03/88,,,MARBRU,Fixed/removed senstivity to TABs in user record
C	  08/05/88,,,MARBRU,Verified conflicting MODPARAMS requests handling
C	  02/02/88,,,MARBRU,Fix record removal, remove upper cased headers
C	  10/26/87,,,MARBRU,Test user MODPARAMS data, remove conflicting records
C	  10/02/87,,,MARBRU,Implemet record sort to fix AUTOGEN "feature"
C		     Also output ATTCAGN records first, add comment line
C	  07/01/87,,137-148312-000,MARBRU,Initial code
C
C  /END MODULE HEADER/        AUOSI 	    /STANDARD MODULE HEADER/
C  *****************************************************************
C
	IMPLICIT 	NONE			! Force ALL declared
C
	Include		'AGN_PAR/NoList'	! AGN  parameters
	Include		'AGN_ERR/Nolist'	! AGN  error mesage codes
	Include		'AGN_FNC/NoList'	! AGN  EXT functions (declared)
C
C	Arguments used:
C
	Logical		PRO			! Product string passed 
	Logical 	DEV			! Device  string passed 
	Logical 	PAR			! Parame  string passed 
	Logical 	TYP			! Par.type string passed
	Logical 	CPU 			! CPU.type string passed
	Logical 	VAL			! Value string passed 
C
	Character*(MPRO)	PROSTR		! Product string
	Character*(MDEV)	DEVSTR		! Device string
	Character*(MPAR)	PARSTR		! Parameter string
	Character*(MTYP)	TYPSTR		! Par.type string
	Character*(MCPU)	CPUSTR		! CPU type string
	Character*(MVAL)	VALSTR          ! VALUE string
	Character*(MDIS)	DISSTR		! Disabled flag string
C
	CHARACTER*(*)		FILSTR		! Input filename string
	INTEGER*4		LFIL		! and length
	Integer*4		IND		! Current record
C
C	Permannent database, has to be declared as SAVE:
C
	Character*255	SAVSTR	/' '/		! Currently loaded file name
	Integer*4	LSAV	/0/		! and length
	Character*(MREC)REC(TREC)		! Array of data file records 
	Integer*4	NREC	/0/		! Records count in a file
	Logical*1	AGN(TREC)		! Flag for ATTC AGN records
      	Logical		RMOD	/.false./	! REC array has been modified
	Save		SAVSTR,LSAV,REC,NREC
	Save		AGN,RMOD
C                                                             
C	Local variables
	Character*(MREC)RECSAV			! Record save for sort
	Character*(MVAL)VALTXT			! Value text string
	Integer*4	IV(TREC)		! Parameter value for sort
	Integer*4	I,J,K		 	! Loop variables        
	Integer*4	LREC			! Record length
	Character*(MPAR)UPAR			! User parameter name for checks
	Character*(MTYP)UTYP,ATYP		! User type, AGN type
	Character*(MVAL)AVAL			! AGN record value
	Integer*4	I1,I2,I3,UVAL		! For User record checks
	Logical		INFORM,REMOVE		! Flags for user records
C                                                                      
C  START OF EXECUTABLE CODE --
C
C	====================================================================
C	This entry creates a new record in our database. It also defines
C	current, suppored ATTC AGN record format for MODPARAMS.DAT.
C	This format is parsed by routines in module AGN_EXT to extract
C	individual items even though file may have been edited.
C
 	ENTRY 	AGN_REC_ADD(PRO,PROSTR,DEV,DEVSTR,CPU,CPUSTR,
     $	                    PAR,PARSTR,TYP,TYPSTR,VAL,VALSTR)
C
	if (NREC.ge.TREC) Call LIB$SIGNAL(AGN$_RECCNT) ! Message, Unwind
	NREC = NREC + 1				! Add a new record
	AGN(NREC)=.true.			! This is AGN record
	RMOD = .true.				! REC array modified
	if (TYP .and. TYPSTR.ne.'VAL') then
	   Write(REC(NREC),390)TYPSTR,PARSTR,VALSTR,PROSTR,'0',DEVSTR,CPUSTR
	else
	   Write(REC(NREC),380)       PARSTR,VALSTR,PROSTR,'0',DEVSTR,CPUSTR
	end if
	RETURN                                                          
C	Max parameter name length anticipated = 16 char (+4 char prefix)
 380	Format 
     $	(1x,a      ,t22,'= ',a,'! ATTCAGN #',a,'#',a,'#',a,'#',a,'#')
 390	Format 
     $	(1x,a,'_',a,t22,'= ',a,'! ATTCAGN #',a,'#',a,'#',a,'#',a,'#')
C                                              
C	====================================================================
C	This entry changes the state of ENABLED/DISABLED flag in particular
C	record. We look for delimiters, since file may have been edited.
C	For MODPARAMS.DAT, we set both flag value and record comment field
C 
	ENTRY	AGN_REC_ENA (IND,DISSTR)
C
	j=    index(REC(IND)(1:),'ATTCAGN') 	! AGN record start
	j=j+index(REC(IND)(j:),'#')		! Product start
	j=j+index(REC(IND)(j:),'#')		! Disabled flag start
	if (REC(IND)(j:j).ne.'0' .and.
     $      REC(IND)(j:j).ne.'1' ) Call LIB$SIGNAL(AGN$_BADREC)
	RMOD = .true.				! Flag database modified
	REC(IND)(j:j)=DISSTR(1:1)      		! Set new flag
	if (DISSTR(1:1).eq.'0')REC(IND)(1:1)=' '! Enable  record for AUTOGEN
	if (DISSTR(1:1).eq.'1')REC(IND)(1:1)='!'! Disable record for AUTOGEN
	Return
C                                                           
C	====================================================================
C	This entry reads the entire file into database
C	It also checks the databese record for compliance with ATTC-AGN
C	syntax (we flag all eligible records with AGN(i) = .true.
C
	Entry	AGN_REC_REA(LFIL,FILSTR)
C
	LSAV    = LFIL				! Assume open failure
	SAVSTR= FILSTR				! and save unqualified name
	NREC	= 0				! Init no records
	RMOD	= .false.			! No records modified
C
	OPEN	(UNIT=1,NAME=FILSTR(:LFIL),
     $	        DEFAULTFILE='sys$system:MODPARAMS.DAT',
     $		TYPE='OLD',READONLY,SHARED,ERR=130)
	INQUIRE	(UNIT=1,NAME=SAVSTR)            ! Get expanded specifier
	LSAV	= index(SAVSTR//' ',' ')	! and remove blanks
	CALL	LIB$SIGNAL(AGN$_INPNAM,%val(1),SAVSTR(:LSAV)) ! Info MSG
C
110	READ    (1,140,ERR=115,END=120)REC(NREC+1)
	NREC	= NREC+1			! Update records count
        AGN(NREC)=.false.			! Assume "foreign" record
	if (index(REC(NREC),'ATTCAGN').ne.0)then! Make sure our records are
	 Call AGN_EXT_LJUST(REC(NREC),REC(NREC))! left justified, uppercase
	 if (index(REC(NREC),'AUTO-TROL').ne.0) then
	     NREC=NREC-1			! Skip any ATTCAGN header
	     GoTo 110 				! record(s)
	 end if
	 if (REC(NREC)(1:1).ne.'!')		! with leading ! comment
     $	     REC(NREC)=' '//REC(NREC)		! or space
         AGN(NREC)=.true.			! Flag as "our" record
	end if                   
 	GOTO	110
115	CLOSE   (UNIT=1)         
	CALL	LIB$SIGNAL(AGN$_INPREA,%val(1),FILSTR(:LFIL))  	! Unwind
C
120	CLOSE   (UNIT=1)         		! Close input file
	If (.not.AGN(1)) then			! If the AGN records is not
	Do i=1,NREC				! first, check if there is any
	   if (AGN(i)) RMOD = .true.		! - if so, set modify flag
	End Do					! to force file update
	end if
	RETURN	              
130	CALL	LIB$SIGNAL(AGN$_INPOPN,%val(1),FILSTR(:LFIL))  	! Warning
	Return							! (no unwind)
140	FORMAT	(a)
C                                                                  
C	====================================================================
C	This special entry locates NEXT record with matching attributes
C	in our  record table. Search starts at IND+1, ends at NREC.
C	Initial call should specify IND = 0.
C	Returned value IND = 0 means "no qualifying record found"
C
     	ENTRY	AGN_REC_LOC(PRO,PROSTR,DEV,DEVSTR,CPU,CPUSTR,
     $	                    PAR,PARSTR,TYP,TYPSTR,IND)
	DO 520 I=IND+1,NREC                                     
	  if (.not.AGN(i)) GoTo 520	! Not an ATTCAGN record
	  if (PRO.and.(AGN_EXT_PRODUCT(REC(i)).ne.PROSTR)) GoTo 520
	  if (DEV.and.(AGN_EXT_DEVICE (REC(i)).ne.DEVSTR)) GoTo 520
	  if (CPU.and.(AGN_EXT_CPUTYP (REC(i)).ne.CPUSTR)) GoTo 520
	  if (PAR.and.(AGN_EXT_PARAM  (REC(i)).ne.PARSTR)) GoTo 520
	  if (TYP.and.(AGN_EXT_TYPE   (REC(i)).ne.TYPSTR)) GoTo 520
	  IND=I                      
	  Return
 520	CONTINUE
	IND = 0				! No matching record found
	Return                                                   
C                               
C	====================================================================
C	This entry removes the record specified by index
C
	ENTRY	AGN_REC_REM(IND)
C  
	Do i=IND,NREC-1			! Move all records 
	   REC(i)=REC(i+1)		! above deleted one
	   AGN(i)=AGN(i+1)		! one position lower
	End Do
	RMOD = .true.			! File records modified
	NREC=NREC-1			! One record less
	RETURN
C
C	====================================================================
C	This entry writes the modified file back as a new version. Many
C	provisions here handle current AUTOGEN problems, so instead of
C	simple writing-out, we SORT ours and check user records.
C
	Entry	AGN_REC_WRT()
C
	If (.not.RMOD) Return			! No modifications to write
	If (LSAV.eq.0) Return			! No file in use
	I            = index(SAVSTR(:LSAV),';')	! Get the semicolon position 
	if (I.eq.0)I = index(SAVSTR(:LSAV),' ')	! No semicolon, use space
	if (I.EQ.0)I = LSAV	
C
	OPEN	(UNIT=1,FILE=SAVSTR(:I),	! Open file with empty version
     $	        DEFAULTFILE='sys$system:MODPARAMS.DAT', !
     $		TYPE='NEW',CARRIAGECONTROL='LIST',ERR=950)
	INQUIRE (UNIT=1,NAME=SAVSTR)		! Get the actual filename
	LSAV 	= index(SAVSTR//' ',' ')	! limited by space
	CALL	LIB$SIGNAL(AGN$_OUTNAM,%val(1),SAVSTR(:LSAV)) ! Inform, cont.
C	
C	Since the AUTOGEN V4.4 trashes subsequent MIN_par (MAX_par) requests 
C	in modparams.dat, we have to sort our records in ascending (descending)
C	order, to make sure the highest MIN (lowest MAX) always gets used.
C	This may STILL OVERRIDE preceeding USER requirements
C
	Do i=1,NREC				! Get the parameter values
	   IV(i)=0				! for sort
	   if (AGN(i)) then			! Here we assume
	      VALTXT=AGN_EXT_VALUE(REC(i))	! all "value" fields are
	      read(VALTXT,*,ERR=600)IV(i)	! NUMERIC
	   end if
 600	   CONTINUE				! 
	end do
	Do i=1,NREC				! Sort by simple swapping
	if (AGN(i) .and. (			! the AGN records
     $	    AGN_EXT_TYPE(REC(i)).eq.'MIN' .or. 		! Look at MIN,MAX,VAL
     $	    AGN_EXT_TYPE(REC(i)).eq.'VAL' .or.		! records only
     $	    AGN_EXT_TYPE(REC(i)).eq.'MAX' )   ) then
	   Do j=i+1,NREC
	   if (AGN(j) .and. 
     $	       AGN_EXT_TYPE (REC(i)).eq.AGN_EXT_TYPE (REC(j)) .and.
     $	       AGN_EXT_PARAM(REC(i)).eq.AGN_EXT_PARAM(REC(j)) .and. (
     $        (AGN_EXT_TYPE (REC(i)).eq.'MAX'.and.IV(i).lt.IV(j)).or.
     $        (AGN_EXT_TYPE (REC(i)).eq.'VAL'.and.IV(i).gt.IV(j)).or.
     $        (AGN_EXT_TYPE (REC(i)).eq.'MIN'.and.IV(i).gt.IV(j)) ))then
	         RECSAV=REC(i)			! Swap records, sorting
	         REC(i)=REC(j)			! MIN and VALs  ascending
	         REC(j)=RECSAV			! MAX descending
	         k = IV(i)			!
	         IV(i)=IV(j)			!
	         IV(j)=k
	   end if ! AGN
	   end do ! j
	end if    ! AGN 
	end do	  ! i
C
	Write(1,940,ERR=970)
     $	'! Auto-trol ATTCAGN records - do not modify nor change order'
	Do i=1,NREC                             ! First write out:
	if(AGN(i))then				! All ATTCAGN records
	  Call STR$TRIM(REC(i),REC(i),LREC)	! but trimmed
	  Write(1,940,ERR=970)REC(i)(:LREC)   	! Write it out
	End If
	End Do
C
 650	Do i=1,NREC				! Last write out:
	if(.not.AGN(i))then			! All non-ATTCAGN records
C	  TEPORRARY checking to solve AUTOGEN 4.6 CODE BUGS:
C	  Make sure user requirement does NOT conflict with a valid ATTCAGN
C	  setup, mainly for MIN and MAX requirements:

	  Call STR$TRIM(REC(i),REC(i),LREC)	! Trim this record
	  Call STR$UPCASE(RECSAV,REC(i))	! and fold up for compares
	  I1=0					! Remove any blanks
	  Do I2=1,LREC				! tabs or other special
	  if (RECSAV(I2:I2).gt.' ') then	! characters, to avoid
	     I1=I1+1				! any paramtere name
	     RECSAV(I1:I1)=RECSAV(I2:I2)	! compare problems
	  end if				!
	  end do				!
	  lrec = I1	  			!
	  I3 = index(RECSAV(:lrec),'!')-1	! Remove comments, if any
	  if (I3.le.0) I3=LREC			! No comments = full record
	  if (I3.le.3 .or. RECSAV(:4).eq.'ADD_') GoTo 660 ! No conflict
	  I1 = 1				! Parameter name start
	  if (RECSAV(:4).eq.'MIN_' .or.
     $	      RECSAV(:4).eq.'MAX_' )   I1 = 5	! Par. name start after MIN_
	  I2 = index(RECSAV(I1:I3),'=')+I1-1	! Find delimiter position
	  if (I2.le.I1) GoTo  660		! No equal sign,  ???
	  UPAR = RECSAV(I1:I2-1)		! Get user parameter name
	  READ (RECSAV(I2+1:I3),*,ERR= 660)UVAL	! Get user value, if any valid
	  UTYP = 'VAL'				! Assume USER record type VAL
	  if (I1.ne.1) UTYP = RECSAV(1:3)	! get USER record type MIN/MAX
	  if (UTYP.eq.'ADD') GoTo  660		! No handling on ADD records
	  INFORM = .false.			! Assume no info needed
	  REMOVE = .false.			! Assume no removal needed
D	  write(*,*)'User:'//UPAR//' typ '//UTYP,UVAL	! Display values
	  Do j=1,NREC
	     if(AGN(j)) then
	     if(UPAR.eq.AGN_EXT_PARAM(REC(j)))then	! Matching parameter
	        if(AGN_EXT_DISABLED(REC(j)).eq.'1')GoTo 655 ! Disabled AGN rec.
	        AVAL = AGN_EXT_VALUE(REC(j))		! Get AGN record value
	        ATYP = AGN_EXT_TYPE (REC(j))		! get AGN record type
	        read(AVAL,*,ERR=655)K			! Get AGN record value
	        if  (ATYP.eq.'ADD') GoTo 655		! No handling
	        if(((ATYP.eq.'MIN'.or.ATYP.eq.'VAL').and.! Here handle VAL,MIN
     $		    (UVAL.ge.K) )			! the same way, since
     $          .or.(ATYP.eq.'MAX' .and.		! For good-overriding 
     $		    (UVAL.le.K) )) then 		! only INFORM the user
		    INFORM = .true.			! 
		else					! For conflicting req.
		    REMOVE = .true.			! Flag to remove
	        end if
	     end if  ! UPAR   match
	     end if  ! AGN(i) true
 655	     Continue! AGN record processing finished target
	  End Do     ! Checking loop
	if ( REMOVE )then
	     CALL LIB$SIGNAL(AGN$_PARCON,%val(1),RECSAV(:I3))
	     CALL LIB$SIGNAL(AGN$_RECCOM)	! give WARNING and 
	     REC(i)='! '//REC(i)(:LREC)		! comment-out user's
	     LREC=LREC+2			! conflicting requirement
	else if ( INFORM ) then
	     CALL LIB$SIGNAL(AGN$_PARMUL,%val(1),RECSAV(:I3))
	end if
 660    Write(1,940,ERR=970)REC(i)(:LREC)   	! Write user rec. out
	End If
	End Do
	CLOSE	(UNIT=1)
	RMOD = .false.				! No modified records
	Return
940	Format  (a)
950	Call 	LIB$SIGNAL(AGN$_OUTOPN,%val(1),SAVSTR(:LSAV)) ! MSG, Unwind
970	Call	LIB$SIGNAL(AGN$_OUTWRT,%val(1),SAVSTR(:LSAV)) ! MSG, Unwind
C	====================================================================
C	The following entry returns all record items/fields
C
	ENTRY AGN_REC_DATA(IND,PROSTR,PARSTR,TYPSTR,CPUSTR,
     $			       DISSTR,VALSTR,DEVSTR)
	PROSTR = AGN_EXT_PRODUCT (REC(IND))
	PARSTR = AGN_EXT_PARAM   (REC(IND))
	TYPSTR = AGN_EXT_TYPE	 (REC(IND))
	CPUSTR = AGN_EXT_CPUTYP  (REC(IND))
	DISSTR = AGN_EXT_DISABLED(REC(IND))
	VALSTR = AGN_EXT_VALUE   (REC(IND))
	DEVSTR = AGN_EXT_DEVICE  (REC(IND))
	RETURN
	END
