.TITLE	LIB_FILE_TRNLOG Translate logical names in file specifier
	.IDENT	/V02.01/

;++TRNFILSPC.MAR
;
; Facility: 
;	Fermilab Accelerator Control System (ACNET) library routine.
;
; Abstract:
;	Translate any logical names used in a file specification.
;
; Environment:
;	Called from user program in USER mode.
;	Stored in FERMILIB.OLB library.
;
;--
;
; Modification History:
;
; Author: F. Nagy			Creation date: 02-Jun-82
;
; V02.00  08-Jun-82	FJN	Changed name and added HELP text header
; V02.01  15-Apr-83	FJN	Standardizing help comments
;
	.PAGE
	.SUBTITLE	Declarations

;
; Include Files:
;
;	NONE
;
; Library Macros:
;
	.NOCROSS
	$SSDEF				;System signal names
	$DSCDEF				;Descriptor fields
	.CROSS
;
; Local Macros:
;
;	NONE
;
; Equated Symbols:
;
strlen = 255				;Length of internal string buffers
escape = ^X1B				;ASCII ESCape character
baoff = 8				;Offset to buffer address in the
					; "extended" string descriptors
;
; Offsets into argument list
;
filein = 4				;Address of input file specification
					; string descriptor
rslbuf = 8				;Address of output file specification
					; string descriptor
rsllen = 12				;Optional: address of word in which the
					; length of the resultant file spec.
					; string is returned.
dsbmsk = 16				;Optional: value of mask to disable the
					; use of specific logical name tables
;
; Offsets to temporary storage on stack (relative to frame pointer, FP)
;
tmp1 = -12				;1st temporary "extended" string descr.
tmp2 = -24				;2nd temporary "extended" string descr.
tsyin = -32				;temp. string descr. for logical name
					; string (input to $TRNLOG)
tsyout = -40				;temp. string descr. for equivalence
					; string (output fom $TRNLOG)
mskint = -44				;Table search disable mask

stkreq = <-mskint> + <2*strlen>		;Total temp space on stack

;
; Program section for code
;
	.PSECT	_LIB_CODE,PIC,USR,CON,REL,LCL,SHR,EXE,NOWRT,RD
	.SHOW	BINARY

	.PAGE
	.SUBTITLE	Translate file specification logical name(s)

;+ LIB_FILE_TRNLOG
; Translate any logical names in a file specification, returning
; as the result a file specification string in which no logical
; names are used.
;
; status.wlc.v = LIB_FILE_TRNLOG(filein.rt.dx, rslbuf.wt.dx,
;                                [rsllen.ww.r], [dsbmsk.rlu.v])
;
;  filein   input file specification.  Passed by descriptor.
;
;  rslbuf   output file specification string.  Passed by descriptor.
;
;  rsllen   (optional) word in which the actual length of the
;           output file specification string is returned.  Passed
;           by reference.
;
;  dsbmsk   value of the logical name table search disable mask.
;           Passed by value.
;
;-
;+0LIB_FILE_TRNLOG
;
; Functional Description:
;	Translates any logical names in a file specification, returning
;	a file specification string in which no logical names appear.
;
; Calling Sequence:
;	status = LIB_FILE_TRNLOG( filein ,rslbuf [,rsllen] [,dsbmsk] )
;
; Input Parameters:
;	filein - address of the string descriptor for the input file
;		specification.
;	dsbmsk - value of the logical name table search disable mask
;
; Implicit Inputs:
;	NONE
;
; Output Parameters:
;	R0 - completion status code
;	rslbuf - address of the string descriptor for the resulting file
;		specification string.
;	rsllen - address of a word in which the (actual) length of the
;		resultant file specification string is returned.
;
; Implicit Outputs:
;	NONE
;
; Condition Codes:
;	SS$_NORMAL - success, file specification string with no logical
;			names returned.
;	SS$_BUFFEROVF - internal buffer overflow during logical name
;			translation or when reconstructing an intermediate
;			form of the file specification string
;	SS$_IVLOGNAM - invalid logical name in file specification string
;	SS$_RESULTOVF - length of resultant string buffer is zero, or
;			resultant file specification string too long to
;			fit in resultant string buffer
;
; Side Effects:
;	System service exception mode is ignored.
;
;-
;!+
;   status = LIB_FILE_TRNLOG( filein,rslbuf,rsllen,dsbmask )
;
; Algorithm:
;
;   IF number_arguments<2 THEN RETURN(INSFARG) ENDIF
;   Allocate stack for temporary variables.
;   Allocate stack for string buffers.
;   tsyin <= filein
;   intfs <= ""
;   tmp <= LOCATE(":",filein)
;   IF tmp<>0 THEN
;	tsyin <= filein<1:tmp-1>
;	intfs <= filein<tmp+1:LEN(filein)>
;	ENDIF
;   status <= NORMAL
;   WHILE status=NORMAL DO
;	status <= $TRNLOG(tsyin,tsyout,,,,dsbmsk)
;	IF status=ERROR THEN
;	    IF status=RESULTOVF THEN status <= BUFFEROVF ENDIF
;	    RETURN(status)
;	    ENDIF
;	IF tsyout<1:1>=ESCAPE THEN
;	    tsyout <= tsyout<5:LEN(tsyout)>
;	    ENDIF
;	IF status=NOTRAN THEN
;	    resfs <= tsyout // ":" // intfs
;	    ELSE
;	    resfs <= tsyout // intfs
;	    tmp <= LOCATE(":",resfs)
;	    IF tmp=0 THEN
;		EXITLOOP
;		ENDIF
;	    tsyin <= resfs<1:tmp-1>
;	    intfs <= resfs<tmp+1:LEN(resfs)>
;	    ENDIF
;	ENDWHILE
;   rslbuf <= resfs
;   rsllen <= LEN(resfs)
;   RETURN(NORMAL)
;!-

	.ENTRY	LIB_FILE_TRNLOG,^M<R2,R3,R4,R5,R6,R7,R8,R9>
	CMPB	(AP),#2			;Require the first 2 arguments
	BGEQU	10$
	MOVZWL	#SS$_INSFARG,R0		;Error return: too few arguments
	RET
;
; Allocate temporary space on stack.  Note that register usage in this
; routine is:
;	R6 - pointer to descriptor of intermediate file spec string
;		(without logical name/device name portion).
;	R7 - pointer to descriptor of internal resultant file spec string
;	R8 - pointer to descriptor of logical name string
;	R9 - pointer to descriptor for equivalence name string
;
10$:	SUBL2	#stkreq,SP		;Adjust stack pointer
	MOVAQ	tmp1(FP),R6		;Setup the descriptor pointer regs
	MOVAQ	tmp2(FP),R7
	MOVAQ	tsyin(FP),R8
	MOVAQ	tsyout(FP),R9
	MOVAB	(SP),baoff(R6)		;Setup buffer address locations
	MOVAB	strlen(SP),baoff(R7)
	MOVL	baoff(R6),DSC$A_POINTER(R6) ;Valid address needed here
	MOVL	baoff(R7),DSC$A_POINTER(R7)
	CLRL	mskint(FP)		;Clear table search disables
	CMPB	(AP),#4			;Check for caller specified disables
	BLSSU	20$
	MOVL	dsbmsk(AP),mskint(FP)	;Use search disable mask from caller
;
; Setup logical name string descriptor to point to device name portion of input
; file specification string.  The intermediate file spec descriptor is setup
; to point to the remainder of the input file spec. string (after the ":") if
; any.
;
20$:	CLRL	DSC$W_LENGTH(R6)	;Init to no intermediate file spec.
	MOVAQ	@filein(AP),R2		;Address of input string descriptor
	MOVL	DSC$A_POINTER(R2),-	;Set pointer to logical name string
		DSC$A_POINTER(R8)
	MOVZWL	DSC$W_LENGTH(R2),-	;Length to be all of input string
		DSC$W_LENGTH(R8)
	LOCC	#^A/:/,-		;Search input string for ":"
		DSC$W_LENGTH(R2),@DSC$A_POINTER(R2)
	BEQL	TRNLOOP			;If no ":", try translating input
	SUBL3	DSC$A_POINTER(R2),R1,-	;Get length of device name portion
		DSC$W_LENGTH(R8)	; for logical name translation
	SUBW3	#1,R0,DSC$W_LENGTH(R6)	;Setup length of renaming portion
	ADDL3	#1,R1,DSC$A_POINTER(R6)	;  and pointer to rest of input
;
; Now translate the logical name, keep trying to translate the "device
; name" portion of the resulting string until no further logical name
; translations are done.
;
TRNLOOP:
	MOVZWL	#strlen,DSC$W_LENGTH(R9) ;Setup descriptor for equivalence
	MOVL	DSC$A_POINTER(R7),-	; string buffer
		DSC$A_POINTER(R9)
	$TRNLOG_S	lognam=(R8),-	;Translate logical name
		rslbuf=(R9),rsllen=DSC$W_LENGTH(R9),-
		dsbmsk=mskint(FP)
	BLBS	R0,SUCCESS		;Check returned condition
	CMPW	R0,#SS$_RESULTOVF	;Check for internal buffer overflow
	BNEQ	XIT1
BUFOVR:	MOVZWL	#SS$_BUFFEROVF,R0	;Return buffer overflow signal
XIT1:	RET
;
; Success, logical name translated or input logical name string copied
; to output (equivalence string).  Append intermediate file specification
; string onto end of equivalence string.
;
SUCCESS:
	SUBL3	#SS$_NORMAL,R0,-(SP)	;Save completion status on stack
	SUBW3	DSC$W_LENGTH(R9),#strlen,R1 ;Get space remaining in buffer
	MOVL	DSC$A_POINTER(R9),R0	;Get address of resultant string
	CMPB	(R0),#escape		;Check for ESCAPE as first character
	BNEQ	10$			;Is it a process permanent file?
	SUBW2	#4,DSC$W_LENGTH(R9)	;Yes, skip ESC and IFI code
	ADDL2	#4,R0
10$:	MOVL	R0,DSC$A_POINTER(R7)	;Setup resultant file string descr.
	MOVZWL	DSC$W_LENGTH(R9),R3	;Get equivalence name string length
	ADDL2	R0,R3			;Point to 1st byte past equiv. string
	TSTL	(SP)			;Check $TRNLOG returned status
	BEQL	20$			;Was it NORMAL (or NOTRAN)?
	MOVB	#^A/:/,(R3)+		;No, add colon after logical name
	DECW	R1			;Reduce space left in buffer
	INCW	DSC$W_LENGTH(R9)	;Count ":" in logical name string
20$:	MOVC5	DSC$W_LENGTH(R6),-	;Append intermediate file spec. string
		@DSC$A_POINTER(R6),-	; onto equivalence string and space
		#^A/ /,-		; fill the (temporary) resultant
		R1,(R3)			; file spec. buffer
	BGTRU	BUFOVR			;Was the buffer overflowed?
	ADDW3	DSC$W_LENGTH(R6),-	;No, setup length of resultant string
		DSC$W_LENGTH(R9),-
		DSC$W_LENGTH(R7)
	TSTL	(SP)+			;Check $TRNLOG return status
	BNEQ	FINIS			;If NOTRAN, then all done
;
; Now check current resultant file specification string for device name portion
; which we will try to translate as a logical name (again).
;
AGAIN:	LOCC	#^A/:/,-		;Search for ":" after device name
		DSC$W_LENGTH(R7),@DSC$A_POINTER(R7)
	BEQL	FINIS			;If no ":", then all done
	SUBL3	DSC$A_POINTER(R7),R1,-	;Subtract buffer "start" and colon-
		DSC$W_LENGTH(R8)	; position pointers to get length
	MOVL	DSC$A_POINTER(R7),-	;Logical name is 1st part of buffer
		DSC$A_POINTER(R8)
	MOVL	R6,R5			;Swap intermediate file spec. descr
	MOVL	R7,R6			; and resultant file spec. descr
	MOVL	R5,R7			; pointers
	MOVL	baoff(R7),-		;Setup resultant file spec. descr
		DSC$A_POINTER(R7)
	SUBW3	#1,R0,DSC$W_LENGTH(R6)	;Setup length of intermediate file
					; spec. string
	ADDL3	#1,R1,DSC$A_POINTER(R6)	;Pointer to intermediate file spec.
	BRW	TRNLOOP			;Translate once more.
;
; All done, either $TRNLOG returned NOTRAN or the equivalence string plus
; the intermediate file spec. string (temp. resultant file spec.) does not
; contain a colon.
;
FINIS:	MOVAQ	@rslbuf(AP),R0		;Get address of caller's resultant
					; file spec. string descriptor
	MOVC5	DSC$W_LENGTH(R7),-	;Move resultant file specification
		@DSC$A_POINTER(R7),-	; from temporary (internal) buffer
		#^A/ /,-		; to caller's resultant string buffer
		DSC$W_LENGTH(R0),-	; with space filling.
		@DSC$A_POINTER(R0)
	BGTRU	RSLOVR			;Did the string fit?
	CMPB	(AP),#3			;Yes, check for rsllen argument
	BLSSU	19$			;Argument list long enough for rsllen?
	MOVL	rsllen(AP),R0		;Yes, get the address of the word
	BEQL	19$			;Was the argument defaulted?
	MOVW	DSC$W_LENGTH(R7),(R0)	;No, set it to the length of the
					; resultant string
19$:	MOVZWL	#SS$_NORMAL,R0		;Return NORMAL success
	RET
;
RSLOVR:	MOVZWL	#SS$_RESULTOVF,R0	;Error: resultant string overflow the
	RET				;  caller's output buffer

	.END