	SUBROUTINE NFSNAME(UNIXNAME,VMSNAME,LVMSNAME)
	IMPLICIT NONE
	CHARACTER*(*) UNIXNAME		!Standard Unix filename
	CHARACTER*(*) VMSNAME		!VMS/NFS converted filename
	INTEGER       LVMSNAME		!Length of converted name
C----------------------------------------------------------------------
C ==> Convert Unix filename to VMS file specification
C----------------------------------------------------------------------
C NFSNAME takes a standard Unix filename (including path) and applies
C the NFS Client rules (TGV Multinet NFS Manual, Section 4.3) to
C produce a VMS file specification suitable for use in accessing the
C file via NFS.  If a root-level directory is included as part of the
C filename, the accessed NFS devices are searched for a match.
C
C Written by Michael H. Kelsey  CITHEX::KELSEY
C
C Copyright (c) 1993  Trustees of the California Institute of Technology
C
C This software is provided on an as-is basis, and no warranty is made
C regarting merchantibility, fitness of use, or suitability for a
C particular purpose.
C
C Version 1.00  KELSEY    20 Aug 91  Program Creation Date
C Version 1.01  KELSEY     1 Aug 93  Release as Freeware package
C----------------------------------------------------------------------
	INCLUDE 'NFSNAME.INC'

C  Local variables
	CHARACTER*(UNIXLEN+1) UTOKEN            !Local conversion
	INTEGER             LTOKEN		!Length of local string
	INTEGER             I, J, K		!Loop variables
	LOGICAL             FIRST /.TRUE./	!Initialization


C  Tokenize filename
	IF (UNIXNAME.EQ.' ') THEN		!Don't process nulls
	  VMSNAME = ' '
	  LVMSNAME = 1
	  RETURN
	ENDIF

	CALL TOKEN_UNIX(UNIXNAME)

C  Convert tokens from Unix to VMS
	DO I=1, NTOKENS
	  VMSTOK(I) = ' '
	  UTOKEN = UNIXTOK(I)
          LTOKEN = LUNIXTOK(I)

	  IF (LTOKEN.NE.0) THEN
            IF ((I.LT.NTOKENS).AND.		!Standard directory
     -	        (UTOKEN.NE.'.').AND.(UTOKEN.NE.'..')) THEN
	      UTOKEN = '.'//UTOKEN
	      LTOKEN = LTOKEN + 1
	    ENDIF

 	    CALL CONV_TOKEN(UTOKEN,LTOKEN,I)
          ENDIF
	ENDDO

C  Map root dir to NFSn: device (and set root VMS directory)
        IF (LUNIXTOK(1).EQ.0) THEN		!Unix file was /dir/...
	  CALL FIND_NFSDEV

	  IF (LNFSDEV.NE.0) THEN		!Strip '.' from top dir
	    VMSTOK(3)  = VMSTOK(3)(2:LVMSTOK(3))
	    LVMSTOK(3) = LVMSTOK(3) - 1
          ELSE
	    VMSTOK(2)  = VMSTOK(2)(2:LVMSTOK(2))
	    LVMSTOK(2) = LVMSTOK(2) - 1
          ENDIF
	ENDIF

C  Construct VMS/NFS file specification
        CALL MAKE_FSPEC(VMSNAME,LVMSNAME)

C  Return NFS file specification
	RETURN
	END


C------------------------------------------------------->>>> TOKEN_UNIX
	SUBROUTINE TOKEN_UNIX(UNIXNAME)
	IMPLICIT NONE
	CHARACTER*(*) UNIXNAME		!Unix file specification string
C----------------------------------------------------------------------
C ==> Split string into Unix tokens
C----------------------------------------------------------------------
C  Take a standard Unix filename and split it into tokens at each
C  directory marker (/).  If the string begins with a directory marker
C  the first token will be empty (length 0).
C----------------------------------------------------------------------
	INCLUDE 'NFSNAME.INC'
        INCLUDE '($STRDEF)'

C  External Routines
	INTEGER  STR$ELEMENT		!Select delimited substring
	INTEGER  STR$TRIM		!Strip trailing blanks

C  Local variables
	INTEGER  ISTAT			!Status flag
        LOGICAL  LAST			!Flag for final token
	CHARACTER*255 DUMMY		!Dummy string for length


C  Initialization
	NTOKENS = 0

C  Loop over tokens until none found
100	CONTINUE
	  NTOKENS = NTOKENS + 1
          ISTAT = STR$ELEMENT(UNIXTOK(NTOKENS),NTOKENS-1,'/',UNIXNAME)
	  IF (ISTAT.EQ.STR$_NOELEM) THEN
	    NTOKENS = NTOKENS - 1
	    GOTO 110
	  ENDIF

	  ISTAT = STR$TRIM(DUMMY,UNIXTOK(NTOKENS),LUNIXTOK(NTOKENS))
	GOTO 100

C  Return token list found
110	CONTINUE
	RETURN
	END


C------------------------------------------------------->>>> CONV_TOKEN
	SUBROUTINE CONV_TOKEN(UNIX, LENUNIX, ITOKEN)
	IMPLICIT NONE
	CHARACTER*(*) UNIX	!Unix token string
	INTEGER       LENUNIX   !Length of Unix string
	INTEGER       ITOKEN	!Index of VMS token
C----------------------------------------------------------------------
C ==> Convert Unix token to VMS/NFS token
C----------------------------------------------------------------------
C This is the meat of the NFSNAME function.  It applies the rules in
C Section 4.3 of the TGV Multinet NFS Manual:
C
C	Unix		VMS/NFS
C       ----		-------
C 1)	'$'		'$$'
C 2)	first '.'	'.' (name/type delimiter)
C 3)    other '.'s	'$5N'
C 4)	8-bit chars	'$nnn' where nnn is octal value (200-377)
C 5)	case-switch	'$' between characters
C 6)	special chars	'$nx' where (4 <= n <= 9) see Table 4-1
C
C It also applies the Unix special directory names:
C
C 1)	'.'		'' (null string)
C 2)	'..'`		'-' (parent directory)
C
C Long filenames (> 39 characters) without filetype delimiters are
C divided at the 38th character with '$.'.  (Per K. Adelman, 930802)
C----------------------------------------------------------------------
	INCLUDE 'NFSNAME.INC'

C  Special character map
	INTEGER     NSPEC	!Number of special character mappings
	PARAMETER  (NSPEC = 63)

        INTEGER     SCHAR(NSPEC)	!ASCII codes
     -	           /   0 ,   1 ,   2 ,   3 ,   4 ,   5 ,   6 ,   7 ,
     -	               8 ,   9 ,  10 ,  11 ,  12 ,  13 ,  14 ,  15 ,
     -	              16 ,  17 ,  18 ,  19 ,  20 ,  21 ,  22 ,  23 ,
     -	              24 ,  25 ,  26 ,  27 ,  28 ,  29 ,  30 ,  31 ,
     -	              32 ,  33 ,  34 ,  35 ,  37 ,  38 ,  39 ,  40 ,
     -	              41 ,  42 ,  43 ,  44 ,  46 ,  47 ,  58 ,  59 ,
     -	              60 ,  61 ,  62 ,  63 ,  64 ,  91 ,  92 ,  93 ,
     -	              94 ,  96 , 123 , 124 , 125 , 126 , 127 /

        CHARACTER*3 SMAP(NSPEC)		!Mapping strings
     -	           /'$6A','$4A','$4B','$4C','$4D','$4E','$4F','$4G',
     -	            '$4H','$4I','$4J','$4K','$4L','$4M','$4N','$4O',
     -	            '$4P','$4Q','$4R','$4S','$4T','$4U','$4V','$4W',
     -	            '$4X','$4Y','$4Z','$6B','$6C','$6D','$6E','$6F',
     -	            '$7A','$5A','$5B','$5C','$5E','$5F','$5G','$5H',
     -	            '$5I','$5J','$5K','$5L','$5N','$5O','$5Z','$7B',
     -	            '$7C','$7D','$7E','$7F','$8A','$8B','$8C','$8D',
     -	            '$8E','$9A','$9B','$9C','$9D','$9E','$9F'/

C  Local Variables
	CHARACTER UCHAR		!Unix token character
	INTEGER   UASC		!ASCII code of Unix character
	CHARACTER*8 VCHAR	!VMS equivalent (up to 4 characters)
	INTEGER     LVCHAR      !Actual length of VMS equivalent
	INTEGER I, J, K		!Loop variables
	LOGICAL CONVDOT		!Flag for mapping periods
	LOGICAL LCASE       	!Flag for case switching

C  Initialization
	VMSTOK(ITOKEN) = ' '
	LVMSTOK(ITOKEN) = 0
	CONVDOT = .FALSE.       !Do not convert first period
	LCASE   = .TRUE.        !Begin with name in lower case

	IF (LENUNIX.EQ.0.OR.UNIX.EQ.' ') RETURN		!Skip nulls

C  Check for special directories
	IF (UNIX.EQ.'.') THEN		!Current directory
	  VMSTOK(ITOKEN)  = ' '
	  LVMSTOK(ITOKEN) = 0
	ELSEIF (UNIX.EQ.'..') THEN	!Parent directory
	  VMSTOK(ITOKEN)  = '.-'
	  LVMSTOK(ITOKEN) = 2
	ELSE				!Need character translation

C  Loop over Unix characters and apply rules
	  DO I=1, LENUNIX
	    UCHAR = UNIX(I:I)
	    UASC  = ICHAR(UCHAR)

	    IF (97.LE.UASC.AND.UASC.LE.122) THEN	!Lower -> Upper
	      VCHAR = CHAR(UASC-32)
	      LVCHAR = 1
	    ELSE					!Keep character
	      VCHAR = UCHAR
	      LVCHAR = 1
	    ENDIF

	    IF (UCHAR.EQ.'$') THEN		!Rule (1)
	      VCHAR = '$$'
	      LVCHAR = 2
	    ELSEIF (UCHAR.EQ.'.') THEN		!Rule (2)
	      IF (.NOT.CONVDOT) THEN
	        VCHAR = '.'
	        LVCHAR = 1
	        CONVDOT = .TRUE.
	      ELSE				!Rule (3)
	        VCHAR = '$5N'
	        LVCHAR = 3
	      ENDIF
	    ELSEIF (UASC.GT.127) THEN		!Rule (4)
	      WRITE (VCHAR,'(A1,O3.3)') '$',UASC
	      LVCHAR = 4
            ELSEIF (LCASE.AND.			!Rule (5) Shift-UP
     -	            (65.LE.UASC.AND.UASC.LE.90)) THEN
	      VCHAR = '$'//VCHAR
	      LVCHAR = 2
	      LCASE = .FALSE.
	    ELSEIF (.NOT.LCASE.AND.		!Rule (5) Shift-DOWN
     -	            (97.LE.UASC.AND.UASC.LE.122)) THEN
	      VCHAR = '$'//VCHAR
	      LVCHAR = 2
	      LCASE = .TRUE.
	    ELSE				!Rule (6)
	      DO J=1, NSPEC
	        IF (UASC.EQ.SCHAR(J)) THEN
	          VCHAR = SMAP(J)
	          LVCHAR = 3
	        ENDIF
	      ENDDO
	    ENDIF				!End of rule matching

C  Break long filenames at 39 characters (K. Adelman)
            IF (.NOT.CONVDOT.AND.LVMSTOK(ITOKEN)+LVCHAR.GE.39) THEN
              VCHAR = '$.'//VCHAR
              LVCHAR = LVCHAR + 2
              CONVDOT = .TRUE.
            ENDIF

C  Append VMS mapping string to end of VMS string
	    IF (LVMSTOK(ITOKEN).EQ.0) THEN
	      VMSTOK(ITOKEN) = VCHAR
	    ELSE
	      VMSTOK(ITOKEN) = VMSTOK(ITOKEN)(1:LVMSTOK(ITOKEN))//VCHAR
	    ENDIF

            LVMSTOK(ITOKEN) = LVMSTOK(ITOKEN) + LVCHAR
	  ENDDO		!Loop over Unix characters

	ENDIF		!End of token conversion

C  Conversion complete
	RETURN
	END


C------------------------------------------------------>>>> FIND_NFSDEV
	SUBROUTINE FIND_NFSDEV
	IMPLICIT NONE
C----------------------------------------------------------------------
C ==> Search mounted NFS devices for Unix rooted directory
C----------------------------------------------------------------------
C This takes the Unix /rootdir token and finds the equivalent NFS-
C mounted device name.  If the Unix directory has not been mounted as
C a device, a null string (LNFSDEV = 0) is returned.
C----------------------------------------------------------------------
	INCLUDE 'NFSNAME.INC'
	INCLUDE '($DVIDEF)'
	INCLUDE '($SSDEF)'

C  External routines
	INTEGER  LIB$GETDVI		!Device information routine

C  Local variables
        INTEGER     INFS                !Index of NFS device
	CHARACTER*6 NFS			!NFS device name ("NFSx")
	CHARACTER*12 NFS_VOLNAM		!NFS volume name (at mount)
	INTEGER  LNFS_VOLNAM		!Length of volume name
        INTEGER  ISTAT			!Return code from LIB$ routines


C  Initialization
        NFSDEV = ' '
	LNFSDEV = 0
	INFS = 0

C  Loop over NFS devices and get information
	DO 100 INFS=0, NFSMAX
	  WRITE (NFS,'(A3,I3.3)') 'NFS',INFS
	  ISTAT = LIB$GETDVI(DVI$_VOLNAM,,NFS,,NFS_VOLNAM,LNFS_VOLNAM)

	  IF (ISTAT.EQ.SS$_NORMAL) THEN
	    IF ('/'//UNIXTOK(2).EQ.NFS_VOLNAM) THEN
	      NFSDEV = NFS//':'
	      LNFSDEV = 7
	      GOTO 110
	    ENDIF
	  ENDIF
100	CONTINUE

C  Return NFS device name
110	CONTINUE
	RETURN
	END


C------------------------------------------------------->>>> MAKE_FSPEC
	SUBROUTINE MAKE_FSPEC(VMSNAME, LVMSNAME)
	IMPLICIT NONE
	CHARACTER*(*) VMSNAME		!VMS file specification (out)
	INTEGER       LVMSNAME		!Length of VMS name (output)
C----------------------------------------------------------------------
C ==> Construct valid VMS file specification from tokens
C----------------------------------------------------------------------
C This takes the list of previously constructed VMS/NFS tokens, and
C an NFS device name (if found), and constructs a file specification
C string from it, including all appropriate delimiters.  The final
C token is assumed to be a filename (*not* a directory) in all cases.
C----------------------------------------------------------------------
	INCLUDE 'NFSNAME.INC'

C  Local variables
	INTEGER  ITOK			!First token for loop
	INTEGER  I, J, K		!Loop variables

C  Initialization
	VMSNAME = ' '
	LVMSNAME = 0

C  If first token is null, then NFS device or rooted directory
	IF (LVMSTOK(1).EQ.0) THEN
	  IF (LNFSDEV.NE.0) THEN        !NFS device from token (2)
	    VMSNAME  = NFSDEV(1:LNFSDEV)
	    LVMSNAME = LNFSDEV
	    ITOK = 3
	  ELSE				!No device, token (2) is dir
	    VMSNAME  = ' '
	    LVMSNAME = 0
	    ITOK = 2
          ENDIF
	ELSE				!Token (1) is top directory
	  VMSNAME  = ' '
	  LVMSNAME = 0
	  ITOK = 1
	ENDIF

C  Loop over remaining tokens except last, and build directory
	IF (ITOK.LT.NTOKENS) THEN
	  IF (LVMSNAME.GT.0) THEN	!Open directory string
	    VMSNAME  = VMSNAME(1:LVMSNAME)//'['
	    LVMSNAME = LVMSNAME + 1
	  ELSE
	    VMSNAME  = '['
	    LVMSNAME = 1
	  ENDIF

	  DO I=ITOK, NTOKENS-1           !Add tokens to directory
	    VMSNAME  = VMSNAME(1:LVMSNAME)//VMSTOK(I)
	    LVMSNAME = LVMSNAME + LVMSTOK(I)
	  ENDDO

	  VMSNAME  = VMSNAME(1:LVMSNAME)//']'	!Terminate directory
	  LVMSNAME = LVMSNAME + 1
	ENDIF

C  Add filename at end of device/directory specification
        IF (LVMSNAME.GT.0) THEN
	  VMSNAME  = VMSNAME(1:LVMSNAME)//VMSTOK(NTOKENS)
	  LVMSNAME = LVMSNAME + LVMSTOK(NTOKENS)
	ELSE
	  VMSNAME  = VMSTOK(NTOKENS)
	  LVMSNAME = LVMSTOK(NTOKENS)
	ENDIF

C  Return constructed VMS file specification
	RETURN
	END
