C************************************************
C*                                              *
C*  CPMDEC--CP/M TO DEC DISK TRANSLATER         *
C*                                              *
C*  NOTE:  MUST BE COMPILED '/NOSWAP'           *
C*                                              *
C*  PROCESSING SCHEME:                          *
C*    THE (SINGLE DENSITY) CP/M DISK IS PHYS-   *
C*    ICALLY THE SAME AS AN RX-01 DISK.         *
C*    THUS WE OPEN DY1: AS A NON-FILE STRUC-    *
C*    TURED DEVICE AND READ IT WITH THE SYSTEM  *
C*    CALL ISPFNW, DOING OUR OWN INTERLEAVING.  *
C*                                              *
C*    RX-01 READS 64 WORD SECTORS (128 BYTES,   *
C*    SAME AS IBM AND CP/M).  THE ISPFNW CALL   *
C*    ALLOWS READING AND WRITING ABSOLUTE       *
C*    PHYSICAL SECTORS.                         *
C*                                              *
C*    MORE INFORMATION ON RX-01 FORMAT DISKS IS *
C*    IN THE DEC PERIPHERALS HANDBOOK.          *
C*                                              *
C*    EACH DISK CONTAINS 77 TRACKS (0..76), OF  *
C*    26 SECTORS EACH.  CP/M INTERLEAVES THE    *
C*    SECTORS; THIS IS TAKEN CARE OF IN SUB     *
C*    DOSEC.  RX-01 USES A DIFFERENT INTERLEAVE *
C*    SCHEME; BUT THIS IS OF NO CONCERN TO US   *
C*    BECAUSE ISPFNW READS ABSOLUTE PHYSICAL    *
C*    SECTORS.                                  *
C*                                              *
C*    CP/M GROUPS 8 LOGICAL SECTORS INTO A      *
C*    CLUSTER (1K) NUMBERED 0..240.  CLUSTERS   *
C*    ARE NUMBERED SEQUENTIALLY STARTING ON     *
C*    TRACK 2; THE DIRECTORY (2K) IS CLUSTERS   *
C*    0 AND 1.  TRACKS 0 AND 1 ARE SYSTEM       *
C*    TRACKS.                                   *
C*                                              *
C*    EACH DIRECTORY ENTRY IS 32 BYTES:         *
C*      1:  0 IF ACTIVE, 0E5H ("345) INACTIVE   *
C*      2-9:  FILE NAME                         *
C*      10-12:  FILE TYPE                       *
C*      13:  EXTENT # [0...]                    *
C*      14-15:  OF NO CONCERN TO US             *
C*      16:  # OF SECTORS IN THIS EXTENT        *
C*        (0..128)                              *
C*      17-32:  NUMBERS, IN ORDER USED, OF UP   *
C*        TO 16 CLUSTERS. (IF FILE IS OVER 16K, *
C*        ANOTHER DIRECTORY ENTRY IS CREATED    *
C*        WITH THE EXTENT # INCREMENTED; AND UP *
C*        TO 16 MORE CLUSTERS ASSIGNED). UNUSED *
C*        CLUSTER ENTRIES ARE 0.                *
C*                                              *
C*  RUSS BAKKE                02-17-83          *
C*                                              *
C************************************************
C
	PROGRAM CPMDEC
C
	BYTE DIR(32,64),CNAME(12),DNAME(16),LBUFF(80)
	BYTE BITMAP(256),DBUFF(1024),MODE(6)
	COMMON DIR
	DATA DNAME/ 'D','Y','0',':',12*0/
	DATA BITMAP/ 2*1,254*0/, MODE /'A','S','C','I','I',' '/
C
	TYPE 100
  100	FORMAT (1X,'CP/M DISK READER, V1.0'//
     +	1X,'INSERT CP/M DISK IN DY1: AND PRESS RETURN'/)
	ACCEPT 104,IWANT
C
C OPEN CP/M DISK AS NON-FILE STRUCTURED DEVICE:
	CALL DSKOPN(ICHAN)
C
C
   10	IPRINT=0
	TYPE 102,MODE
  102	FORMAT (/,1X,'COPY MODE IS ',6A1,/,
     +	1X,'ENTER NUMBER OF OPTION DESIRED:',/,
     +	1X,'1.  DISPLAY CP/M DIRECTORY.',/,
     +	1X,'2.  PRINT CP/M DIRECTORY.',/,
     +	1X,'3.  COPY A FILE FROM CP/M DISK.',/,
     +	1X,'4.  COPY ALL FILES FROM CP/M DISK TO DY0:',/,
     +	1X,'5.  INITIALIZE A CP/M DISK.',/,
     +	1X,'6.  DELETE A FILE FROM CP/M DISK.',/,
     +	1X,'7.  COPY FILE TO CP/M DISK.',/,
     +	1X,'8.  CHANGE COPY MODE.',/,
     +	1X,'9.  QUIT.')
	ACCEPT 104,IWANT
  104	FORMAT (I2)
	IF (IWANT .LT. 1 .OR. IWANT .GT. 9) GOTO 10
	IF (IWANT .EQ. 1) GOTO 11
	IF (IWANT .EQ. 3) GOTO 30
	IF (IWANT .EQ. 4) GOTO 40
	IF (IWANT .EQ. 5) GOTO 50
	IF (IWANT .EQ. 6) GOTO 60
	IF (IWANT .EQ. 7) GOTO 70
	IF (IWANT .EQ. 8) GOTO 62
	IF (IWANT .EQ. 9) GOTO 99
C
C  FALL THROUGH IS 2 (PRINT DIRECTORY OF CP/M DISK)
	IPRINT=1
C
C  DISPLAY DIRECTORY
   11	CALL GETDIR(ICHAN)	!READ DIRECTORY
	ITOTAL=0
C
C  DISPLAY DIRECTORY
	DO 12 I=1,80	!CLEAR LBUFF
	LBUFF(I) = ' '
   12	C O N T I N U E
	IBFPTR = 0
C
	DO 24 INDEX=1,64
	IF (DIR(1,INDEX) .EQ. "345) GOTO 24	!EMPTY ENTRY
	IF (DIR(13,INDEX) .NE. 0) GOTO 24	!LATER EXTENT
	ISIZE = DIR(16,INDEX)
	IF (ISIZE .LT. 0) ISIZE=ISIZE+256
	IF (ISIZE .EQ. 128) GOTO 14	!MULTIPLE EXTENTS
	ISIZE = (ISIZE+7)/8
	GOTO 22
C
C  MULTIPLE EXTENT FILE; MUST GET SIZE FROM LATER EXTENTS
   14	DO 16 IPTR=2,12
	CNAME(IPTR-1)=DIR(IPTR,INDEX)
   16	C O N T I N U E
	IEXT=1
   18	ISIZE=0
	CALL FIND (CNAME,IEXT,IENTRY)
	IF (IENTRY .EQ. -1) GOTO 20	!NO MORE EXTENTS
	ISIZE=DIR(16,IENTRY)
	IF (ISIZE .LT. 0) ISIZE=ISIZE+256
	IF (ISIZE .NE. 128) GOTO 20	!NO MORE EXTENTS
	IEXT=IEXT+1
	GOTO 18
C
   20	ISIZE=(ISIZE+7)/8 + 16*IEXT
C
   22	ENCODE(16,120,LBUFF(18*IBFPTR+2))
     +	(DIR(J,INDEX),J=2,12),ISIZE
  120	FORMAT (8A,'.',3A,I3,'K')
	ITOTAL=ITOTAL+ISIZE
	IBFPTR = IBFPTR+1
	IF (IBFPTR .LE. 3) GOTO 24
C
C  NEED TO PRINT & CLEAR LBUFF
	IF (IPRINT .EQ. 0) TYPE 122,LBUFF
	IF (IPRINT .EQ. 1) PRINT 122,LBUFF
  122	FORMAT (1X,80A1)
	DO 23 I=1,80
	LBUFF(I) = ' '
   23	C O N T I N U E
	IBFPTR = 0
C
   24	C O N T I N U E
	IF (IPRINT .EQ. 1) GOTO 25
	TYPE 122,LBUFF
	TYPE *,'TOTAL BYTES = ',ITOTAL,'K'
	GOTO 10
C
   25	PRINT 122,LBUFF
	PRINT *,'TOTAL BYTES = ',ITOTAL,'K'
	GOTO 10
C
C COPY A FILE FROM CP/M DISK
C
C GET CP/M NAME
   30	CALL GTCPMF(CNAME)
	CALL GETDIR(ICHAN)
C
C  LOOKUP CNAME IN DISK DIR
	CALL FIND(CNAME,0,IENTRY)
	IF (IENTRY .NE. -1) GOTO 32	!OK
   31	TYPE *,'FILE NOT FOUND'
	GOTO 10
C
C  GET DEC NAME & OPEN
   32	CALL GETFN('OUTPUT',IDCHAN)
C  READ FILE AND WRITE TO DEC
	CALL CPYFIL(IENTRY,CNAME,ICHAN,IDCHAN,MODE(1))
C
C  CPYFIL CLOSES AND FREES THE CHANNEL
   34	TYPE *,'COPY COMPLETED'
	GOTO 10
C
C
C  COPY ALL FILES FROM CP/M DISK TO DY0:
   40	TYPE *,'INSERT BLANK DEC DISK IN DY0: AND PRESS RETURN'
	ACCEPT 104,IWANT
	CALL GETDIR(ICHAN)
	DO 48 IENTRY=1,64
	IF (DIR(1,IENTRY) .EQ. "345) GOTO 48
	IF (DIR(13,IENTRY) .NE. 0) GOTO 48
	DO 42 IPTR=2,12
	CNAME(IPTR-1)=DIR(IPTR,IENTRY)	!SAVE NAME
   42	C O N T I N U E
C  NOW CONVERT CNAME INTO DEC NAME, IN DNAME
	DO 44 IPTR=1,6
	IF (CNAME(IPTR) .EQ. ' ') GOTO 46
	DNAME(IPTR+4) = CNAME(IPTR)
   44	C O N T I N U E
   46	DNAME(IPTR+4)='.'
	DNAME(IPTR+5) = CNAME(9)
	DNAME(IPTR+6) = CNAME(10)
	DNAME(IPTR+7) = CNAME(11)
	DNAME(IPTR+8) = 0
	DNAME(4)=':'
C
	TYPE 124,(CNAME(J),J=1,11),DNAME
  124	FORMAT (1X,'COPYING CP/M FILE ',8A,'.',3A,'  TO DEC FILE ',16A)
C
C  NOW OPEN DEC FILE (AS CHANNEL IDCHAN)
	CALL DECOPN(DNAME,IDCHAN,'O')
	IFILE=IENTRY
	CALL CPYFIL(IFILE,CNAME,ICHAN,IDCHAN,MODE(1))
   48	C O N T I N U E
	GOTO 34
C
C
C  INITIALIZE A CP/M DISK
   50	TYPE *,'INITIALIZE--ARE YOU SURE?'
	ACCEPT 126,IWANT
  126	FORMAT(A1)
	IF (IWANT .NE. 'Y') GOTO 10
C
C  (WRITE E5H THROUGHOUT DIRECTORY)
	DO 54 I=1,32
	DO 52 J=1,64
	DIR(I,J)="345
   52	C O N T I N U E
   54	C O N T I N U E
   56	CALL PUTDIR(ICHAN)
	TYPE *,'COMPLETED'
	GOTO 10
C
C
C  DELETE A CP/M FILE
   60	CALL GTCPMF(CNAME)
	CALL ERASE(CNAME,ICHAN,ISTAT)
	IF (ISTAT .EQ. -1) GOTO 31	!UNSUCCESSFUL
	GOTO 56		!WRITE DIR & RET TO MENU
C
C
C  TOGGLE COPY MODE
   62	IF (MODE(1) .EQ. 'A') GOTO 64
	MODE(1) = 'A'
	MODE(2) = 'S'
	MODE(3) = 'C'
	MODE(4) = 'I'
	MODE(5) = 'I'
	MODE(6) = ' '
	GOTO 10
C
   64	MODE(1) = 'B'
	MODE(2) = 'I'
	MODE(3) = 'N'
	MODE(4) = 'A'
	MODE(5) = 'R'
	MODE(6) = 'Y'
	GOTO 10
C
C
C  WRITE A CP/M FILE
C  GET DEC NAME & OPEN
   70	CALL GETFN('INPUT ',IDCHAN)
	IDBLK=0
C  GET CP/M FILE NAME
	CALL GTCPMF(CNAME)
C
C  IF WE ALREADY HAVE A FILE BY THIS NAME, ERASE IT
	CALL ERASE(CNAME,ICHAN,ISTAT)
C
C  NOW FOR THE HARD PART.
C  WE MUST READ THE CP/M DIRECTORY; MAKE A BIT MAP
C  (ACTUALLY BYTE MAP) OF CLUSTERS USED; CREATE A
C  CP/M DIRECTORY ENTRY; ASSIGN EACH CLUSTER, READ
C  8*128 BYTES WITH IREADW AND WRITE THEM TO THE
C  CP/M DISK.
C
	DO 72 I=1,64
	IF (DIR(1,I) .EQ. "345) GOTO 72	!NOT ALLOCATED
	DO 71 J=17,32
	IDIREN=DIR(J,I)
	IF (IDIREN .EQ. 0) GOTO 72	!NOT ALLOCATED
	IF (IDIREN .LT. 0) IDIREN = IDIREN+256
	IF (IDIREN .LT.0 .OR. IDIREN .GT. 255) STOP 'MAP ERROR'
	BITMAP (IDIREN+1) = 1
   71	C O N T I N U E
   72	C O N T I N U E
C
C  NOW FIND AN OPEN DIR ENTRY
	IEXT=0
   73	DO 74 IENTRY=1,64
	IF (DIR(1,IENTRY) .EQ. "345) GOTO 75
   74	C O N T I N U E
	STOP 'DIRECTORY FULL'
C
C  COPY IN FILE NAME
   75	DIR(1,IENTRY)=0
	DO 76 J=2,12
	DIR(J,IENTRY)=CNAME(J-1)
   76	C O N T I N U E
	DO 77 J=13,32
	DIR(J,IENTRY)=0
   77	C O N T I N U E
	IBLK=1
	ISIZE=0
	DIR(13,IENTRY)=IEXT
C
C ALLOCATE A CLUSTER
   78	DO 79 ICLU=3,241
	IF (BITMAP(ICLU) .EQ. 0) GOTO 80	!FOUND A FREE CLUSTER
   79	C O N T I N U E
	STOP 'CP/M DISK FULL'
C
C  WRITE CLUSTER NUMBER TO DIRECTORY
   80	BITMAP(ICLU)=1
	ICLU=ICLU-1		!0-255 NOT 1-256
	DIR(IBLK+16,IENTRY)=ICLU
C  CONVERT CLUSTER # TO SECTOR AND TRACK
	ITEMP=8*ICLU
	ISTTRK=ITEMP/26
	ISTART=ITEMP-26*ISTTRK+1
	ISTTRK=ISTTRK+2
C
C  READ 8 SECTORS FROM DEC DISK
	IRET=IREADW(512,DBUFF,IDBLK,IDCHAN)
	IDBLK=IDBLK+2
C  ERRORS ARE:
C  -1: EOF
C  -2: HARDWARE ERROR
C  -3: CHANNEL NOT OPEN
C  OR IF IRET = 256, ONLY 1 BLOCK READ
	IF (IRET .EQ. 256) GOTO 96	!1 BLOCK
	IF (IRET .GE. 0) GOTO 81
	IF (IRET .EQ. -1) GOTO 97	!EOF
	TYPE *,'IREAD ERROR TYPE ',IRET
	STOP
C
C  WRITE 8 SECTORS
   81	ILIMIT=7
   83	IF (MODE(1) .EQ. 'B') GOTO 93
C
C  FIND EOF, INSERT CTL-Z (CP/M EOF)
	DO 84 INDEX2=128*(ILIMIT+1),1,-1
	IF (DBUFF(INDEX2) .NE. 0) GOTO 85
   84	C O N T I N U E
   85	IF (INDEX2 .LT. 128*(ILIMIT+1)) DBUFF(INDEX2+1) = 26 !CTL-Z
C
   93	DO 95 ISEC=0,ILIMIT
	ITEMP=ISTART+ISEC
	ITRK=ISTTRK
	IF (ITEMP .LE. 26) GOTO 94
	ITEMP=ITEMP-26
	ITRK=ITRK+1
   94	CALL DOSEC('W',ITRK,ITEMP,DBUFF(128*ISEC+1),ICHAN)
	ISIZE=ISIZE+1
   95	C O N T I N U E
	IF (IRET .EQ. 0) GOTO 97
C
C  NEED ANOTHER CLUSTER
	IBLK=IBLK+1
	IF (IBLK .LE. 16) GOTO 78
C  NEED A NEW EXTENT
	DIR(16,IENTRY)=128	!SET SECTOR COUNT
	IEXT=IEXT+1
	TYPE *,'WORKING. . .'
	GOTO 73
C
C  ONLY 4 SECTORS READ FROM DEC FILE
   96	ILIMIT=3
	IRET=0
	GOTO 83
C
C  THAT'S ALL
   97	DIR(16,IENTRY)= ISIZE	!SET SIZE
C  WRITE OUT DIRECTORY
	CALL PUTDIR(ICHAN)
	CALL ICLOSE(IDCHAN)
	CALL IFREEC(IDCHAN)
	GOTO 34
C
C
C  CLOSE
   99	CALL ICLOSE (ICHAN)
	CALL IFREEC (ICHAN)
	CALL EXIT
	END
C
	SUBROUTINE DSKOPN (IDCH)
C****************************************************
C*                                                  *
C*  OPEN FLOPPY DISK DRIVE 1 AS NON-FILE            *
C*  STRUCTURED DEVICE; RETURN CHANNEL NO. IN IDCH.  *
C*                                                  *
C*  RUSS BAKKE                      02-10-83        *
C*                                                  *
C****************************************************
C
	REAL*4 DISK1
	DATA DISK1 /3RDY1   /
C
C  FETCH HANDLER, OPEN A CHANNEL, LOOKUP DEVICE
	IF (IFETCH(DISK1) .NE. 0) STOP 'IFETCH ERROR
     +	IN DSKOPN'
	IDCH=IGETC()
	IF(IDCH.LT.0) STOP' NO CHANNEL AVAILABLE'
C
	IRET = LOOKUP(IDCH,DISK1)
	IF (IRET .GE. 0) GOTO 10
C
C  LOOKUP FAILURE
	TYPE *,'LOOKUP FAILURE TYPE ',IRET
	STOP
C
   10	RETURN
	END
C
	SUBROUTINE GETDIR(ICHAN)
C****************************************************
C*                                                  *
C*  READ DIRECTORY OF CP/M DISK.                    *
C*                                                  *
C*  THE CP/M DISK USES TRACKS 0 AND 1 FOR SYSTEM    *
C*  TRACKS; WE MAY IGNORE THEM.  THE DIRECTORY IS   *
C*  2K OR 16 SECTORS, STARTING ON TRACK 2.          *
C*                                                  *
C*  RUSS BAKKE                  05-06-82            *
C*                                                  *
C****************************************************
C
	BYTE DIR(32,64)
	COMMON DIR
C
	DO 80 INDEX=1,16
	ISECTR=INDEX
	CALL DOSEC('R',2,ISECTR,DIR(1,4*(ISECTR-1)+1),ICHAN)
   80	C O N T I N U E
	RETURN
	END
C
	SUBROUTINE PUTDIR(ICHAN)
C****************************************************
C*                                                  *
C*  WRITE DIRECTORY OF CP/M DISK.                   *
C*  (SIMILAR TO GETDIR).                            *
C*                                                  *
C*  RUSS BAKKE                  05-25-82            *
C*                                                  *
C****************************************************
C
	BYTE DIR(32,64)
	COMMON DIR
C
	DO 80 INDEX=1,16
	ISECTR=INDEX
	CALL DOSEC('W',2,ISECTR,DIR(1,4*(ISECTR-1)+1),ICHAN)
   80	C O N T I N U E
	RETURN
	END
C
	SUBROUTINE DOSEC(RW,ITRK,ISEC,BUFF,ICHAN)
C****************************************************
C*                                                  *
C*  READ/WRITE (RW IS DIRECTION) LOGICAL SECTOR     *
C*  'ISEC', TRACK 'ITRK', TO/FROM 'BUFF' (128       *
C*   BYTES), FROM/TO CHANNEL 'ICHAN'.               *
C*                                                  *
C*  RUSS BAKKE                   05-12-82           *
C*                                                  *
C****************************************************
C
	BYTE BUFF(128),MYBUFF(130),RW
	INTEGER ITABLE(26)
	DATA ITABLE /1,7,13,19,25,5,11,17,23,3,9,15,21,2,8,
     +	14,20,26,6,12,18,24,4,10,16,22/
C  ITABLE IS THE CP/M SECTOR INTERLEAVE TABLE (26 SECTORS PER TRACK)
C  PHYSICAL SECTOR # [1..26] = ITABLE(LOGICAL SECTOR # [1..26])
C
	IF (RW .EQ. 'W') GOTO 50
	IRET=ISPFNW("377,ICHAN,ITRK,MYBUFF,ITABLE(ISEC))
C
C  THE ISPFNW CALL IS AS FOLLOWS:
C  IRET=ISPFNW(FUNC,ICHAN,ITRK,BUFF,SECTOR)
C    FUNC="377 FOR READ, "376 FOR WRITE
C    ICHAN=CHANNEL #, FROM LOOKUP
C    ITRK=ABSOLUTE PHYSICAL TRACK #, 0..76
C    SECTOR=ABSOLUTE PHYSICAL SECTOR #, 1..26
C    BUFF=128 BYTE BUFFER
C    IRET RETURNS:
C	0 NORMAL
C	1  EOF
C	2  HARDWARE ERROR
C	3  CHANNEL NOT OPEN
C
	IF (IRET .EQ. 0) GOTO 40
   30	TYPE 100,RW,ITRK,ISEC
  100	FORMAT (1X,A,2X,'TRACK: ',I3,'   LOG. SECTOR: ',I3)
	IF (IRET .EQ. 1) STOP 'CHANNEL EOF IN DOSEC'
	IF (IRET .EQ. 2) STOP 'HARDWARE ERROR IN DOSEC'
	IF (IRET .EQ. 3) STOP 'CHANNEL NOT OPEN IN DOSEC'
	STOP 'ERROR IN DOSEC'
C
C  WE MUST READ INTO 130 BYTE BUFFER, BECAUSE ISPFNW READS
C  LEADING 0 WORD INTO BUFFER.  (THIS IS DOCUMENTED IN THE
C  SOFTWARE SUPPORT MANUAL BUT NOT IN THE PROGRAMMER'S REFERENCE).
   40	DO 45 I=1,128
	BUFF(I) = MYBUFF(I+2)
   45	C O N T I N U E
	RETURN
C
C  WRITING
   50	DO 55 I=1,128
	MYBUFF(I+2)=BUFF(I)
   55	C O N T I N U E
	MYBUFF(1)=0
	MYBUFF(2)=0
C
	IRET=ISPFNW("376,ICHAN,ITRK,MYBUFF,ITABLE(ISEC))
	IF (IRET .NE. 0) GOTO 30
	RETURN
	END
C
	SUBROUTINE GTCPMF(CNAME)
C****************************************************
C*                                                  *
C*  GET CP/M NAME, AND FORMAT INTO CNAME.           *
C*                                                  *
C*  RUSS BAKKE                  05-05-82            *
C*                                                  *
C****************************************************
C
	BYTE CNAME(12),TYPE(3)
C
	TYPE *,'ENTER CP/M FILE NAME:'
	ACCEPT 110,CNAME
  110	FORMAT(12A1)
C
C  NOW REFORMAT TO 8 CHAR NAME & 3 CHAR TYPE
C  FIND '.'
	DO 10 INDEX=1,12
	IF (CNAME(INDEX) .EQ. '.') GOTO 20
   10	C O N T I N U E
	GOTO 90	!NO '.', PASS WHAT WE GOT
C
C  EXTRACT FILE TYPE
   20	DO 30 INDEX2=1,3
	TYPE(INDEX2) = CNAME(INDEX+INDEX2)
   30	C O N T I N U E
C  FILL CNAME FROM PERIOD THROUGH 12 WITH SPACES
	DO 40 INDEX2=INDEX,12
	CNAME(INDEX2) = ' '
   40	C O N T I N U E
C  COPY TYPE INTO CNAME
	DO 50 INDEX2=1,3
	IF (TYPE(INDEX2) .EQ. 0) GOTO 90
	CNAME(8+INDEX2) = TYPE(INDEX2)
   50	C O N T I N U E
   90	RETURN
	END
C
	SUBROUTINE GETFN(PROMPT,IDCHAN)
C********************************************************
C*                                                      *
C*  INPUT A FILE NAME AND OPEN A DEC FILE.  RETURN THE  *
C*  CHANNEL NUMBER IN IDCHAN.                           *
C*                                                      *
C*   RUSS BAKKE             05-11-82                    *
C*                                                      *
C********************************************************
C
	LOGICAL*1 FNAME(16),PROMPT(6)
C
    5	WRITE (7,103) PROMPT
  103	FORMAT (1X,6A1,' FILE SPECIFICATION?')
C
    8	READ (5,105) FNAME
  105	FORMAT (16A1)
	FNAME(16)=0
C	CHECK TO AVOID NULL FILE NAME
	IF (FNAME(1) .EQ. ' ') GOTO 70
	IF (FNAME(3) .EQ. ':' .AND. FNAME(4) .EQ. ' ') GOTO 70
	IF (FNAME(4) .EQ. ':' .AND. FNAME(5) .EQ. ' ') GOTO 70
C
	CALL DECOPN(FNAME,IDCHAN,PROMPT(1))
	RETURN
C
   70	TYPE *,'ERROR IN FILE SPECIFICATION, TRY AGAIN'
	GOTO 5
	END
C
	SUBROUTINE DECOPN(FNAME,IDCHAN,RW)
C**************************************************
C*                                                *
C*  OPEN A DEC FILE FNAME, RETURNING CHANNEL      *
C*  NUMBER IN IDCHAN.  RW IS READ/WRITE.          *
C*                                                *
C*  RUSS BAKKE               05-25-82             *
C*                                                *
C**************************************************
C
	BYTE FNAME(16),RW
	REAL*8 FSPEC
C
C  CONVERT FNAME TO RADIX 50
C
C  REFORMAT AS DL0FNAME_TYP
C  FIRST FIND ':'
	DO 20 I=1,16
	IF (FNAME(I) .EQ. ':') GOTO 25
   20	C O N T I N U E
C  NO ':' FOUND, INSERT 'DL0'
	DO 22 I=13,1,-1
	FNAME(I+3)=FNAME(I)
   22	C O N T I N U E
	FNAME(1)='D'
	FNAME(2)='L'
	FNAME(3)='0'
	GOTO 30
C
C  EAT THE ':'
  25	DO 28 J=I,15
	FNAME(J)=FNAME(J+1)
   28	C O N T I N U E
	FNAME(16)=' '
C
C  NOW FIND '.'
   30	DO 35 I=1,16
	IF (FNAME(I) .EQ. '.') GOTO 36
   35	C O N T I N U E
C  NO '.' FOUND
	GOTO 40
C
C  MOVE TYPE TO LAST 3 CHARS
   36	FNAME(16)=FNAME(I+3)
	FNAME(15)=FNAME(I+2)
	FNAME(14)=FNAME(I+1)
	FNAME(10)=FNAME(14)
	FNAME(11)=FNAME(15)
	FNAME(12)=FNAME(16)
C
C  BLANK FILL
	IF (I .GE. 10) GOTO 40
	DO 38 J=I,9
	FNAME(J)=' '
   38	C O N T I N U E
C
C  CHANGE ALL ILLEGAL CHARACTERS TO '9'
   40	DO 42 INDEX=4,12
	IF (FNAME(INDEX) .GE. 'A' .AND.
     +	FNAME(INDEX) .LE. 'Z') GOTO 42		!OK
	IF (FNAME(INDEX) .GE. '0' .AND.
     +	FNAME(INDEX) .LE. '9') GOTO 42		!OK
	IF (FNAME(INDEX) .EQ. ' ' .OR.
     +	FNAME(INDEX) .EQ. '.') GOTO 42		!OK
	FNAME(INDEX) = '9'
   42	C O N T I N U E
C
C  NOW CONVERT TO RADIX 50
	IDUM=IRAD50(12,FNAME,FSPEC)
C
C  GET A CHANNEL
	IDCHAN=IGETC()
	IF(IDCHAN .LT. 0) STOP' NO CHANNEL AVAILABLE'
C
	IF (RW .EQ. 'O') GOTO 50
	IRET = LOOKUP(IDCHAN,FSPEC)
	IF (IRET .GE. 0) GOTO 90
C
C  LOOKUP FAILURE--TYPES ARE:
C  -1: CHANNEL ALREADY OPEN
C  -2: SPECIFIED FILE NOT FOUND
C  -3: DEVICE IN USE
C  -4: TAPE ONLY
	IF (IRET .NE. -2) GOTO 45
	STOP 'DEC FILE NOT FOUND'
C
   45	TYPE *,'LOOKUP FAILURE TYPE ',IRET
	STOP
C
C  WRITE FILE MUST USE IENTER NOT LOOKUP
   50	IRET=IENTER(IDCHAN,FSPEC,-1)
	IF (IRET .GE. 0) GOTO 90
C  IENTER ERRORS ARE:
C  -1: CHANNEL ALREADY OPEN
C  -2: NO SPACE AVAILABLE
C  -3: DEVICE IN USE
C  -4: FILE EXISTS AND IS PROTECTED
C  -5: CASSETTE ONLY
	TYPE *,'IENTER FAILURE TYPE ',IRET
	STOP
C
   90	RETURN
	END
C
	SUBROUTINE FIND(CNAME,EXT,IENTRY)
C****************************************************
C*                                                  *
C*  FIND CP/M FILE NAMED CNAME IN DIRECTORY (IN     *
C*  DIR, PASSED IN COMMON), EXTENT 'EXT'; RETURN    *
C*  DIRECTORY ENTRY NUMBER IN IENTRY.               *
C*                                                  *
C*  RUSS BAKKE                    05-11-82          *
C*                                                  *
C****************************************************
C
	BYTE DIR(32,64),CNAME(12)
	INTEGER EXT
	COMMON DIR
C
	DO 44 IENTRY=1,64
	IF (DIR(1,IENTRY) .EQ. "345) GOTO 44	!EMPTY, SKIP
	DO 42 ICHAR=2,12
	IF (DIR(ICHAR,IENTRY) .NE. CNAME(ICHAR-1)) GOTO 44
   42	C O N T I N U E
C  FALL THROUGH MEANS A MATCH
	IF (DIR(13,IENTRY) .EQ. EXT) GOTO 90	!FOUND IT
C
   44	C O N T I N U E
C  FALL THROUGH MEANS NO MATCH FOUND
	IENTRY=-1
   90	RETURN
	END
C
	SUBROUTINE CPYFIL(IENTRY,CNAME,ICHAN,IDCHAN,MODE)
C*************************************************
C*                                               *
C*  COPY CP/M FILE (ICHAN) TO DEC FILE (IDCHAN). *
C*  CP/M DIRECTORY ENTRY IS 'IENTRY'.            *
C*  MODE IS "BINARY" OR "ASCII ".                *
C*  CLOSE DEC CHANNEL (IDCHAN) WHEN FINISHED.    *
C*                                               *
C*  RUSS BAKKE                      02-02-83     *
C*                                               *
C*************************************************
C
	BYTE DIR(32,64),DBUFF(1024),CNAME(12),MODE
	COMMON DIR
C
	IDBLK=0	!DISK BLOCK TO WRITE
	IEXT=0	!FIRST EXTENT
C
    8	ICLU=1	!FIRST CLUSTER
	ISIZE=DIR(16,IENTRY)
	IF (ISIZE .LT. 0) ISIZE=ISIZE+256
	IF (ISIZE .EQ. 128) ISIZE=129	!DON'T LET IT COUNT OUT
   10	IF (ISIZE .EQ. 0) GOTO 90
	IBLK=DIR(16+ICLU,IENTRY)
	IF (IBLK .LT. 0) IBLK=IBLK+256
C  (PROBLEM HERE, IS WE GET SIGN EXTENSION ON READING BYTE
C  VALUE INTO INTEGER VARIABLE)
	IF (IBLK .EQ. 0) GOTO 90	!THAT'S ALL
C
C  NEED TO READ 'IBLK' 1K CLUSTER (8 SECTORS)
C
C  CONVERT IBLK TO STARTING SECTOR # AND TRACK #
C  MULTIPLY BY 8 AND REDUCE MODULO 26
	ITEMP=8*IBLK
	ISTTRK=ITEMP/26
	ISTART=ITEMP-26*ISTTRK+1
	ISTTRK=ISTTRK+2	!SKIP SYSTEM TRACKS
C
	DO 60 ISECTR=0,7
	ITEMP=ISTART+ISECTR
	ITRK=ISTTRK
	IF (ITEMP .LE. 26) GOTO 30
	ITEMP=ITEMP-26
	ITRK=ITRK+1
   30	CALL DOSEC('R',ITRK,ITEMP,DBUFF(128*ISECTR+1),ICHAN)
	ISIZE=ISIZE-1
	IF (ISIZE .LE. 0) GOTO 80
   60	C O N T I N U E
C
C  NOW WRITE BUFF TO IDCHAN
C  SEARCH BUFFER FOR CTL-Z (EOF) UNLESS BINARY MODE.
	IF (MODE .EQ. 'B') GOTO 70
   62	DO 65 INDEX=1,1024
	IF (DBUFF(INDEX) .EQ. 26) GOTO 75
   65	C O N T I N U E
C
   70	IRET=IWRITW(512,DBUFF,IDBLK,IDCHAN)
	IDBLK=IDBLK+2
C  IWRITW RETURNS:
C  -1: EOF
C  -2: HARDWARE ERROR
C  -3: CHANNEL NOT OPEN
C
	IF (IRET .LT. 0) GOTO 95
	ICLU=ICLU+1
	IF (ICLU .LT. 17) GOTO 10	!NEXT SEGMENT
C
C  NOW SEE IF WE HAVE ANOTHER EXTENT
	IEXT=IEXT+1
	CALL FIND(CNAME,IEXT,IENTRY)
	IF (IENTRY .NE. -1) GOTO 8	!NEXT EXTENT
	GOTO 90
C
C  HAVE EOF AT "INDEX"
   75	DO 78 INDEX1=INDEX,1024
	DBUFF(INDEX1)=0		!NULL FILL FOR DEC
   78	C O N T I N U E
	IF (INDEX .LE. 512) GOTO 83
	GOTO 84
C
C  HAVE PARTIAL BUFFER--WRITE IT OUT.
   80	IF (MODE .EQ. 'A') GOTO 62
	DO 82 IPTR=128*(ISECTR+1)+1,1024
	DBUFF(IPTR)=0
   82	C O N T I N U E
	IF (ISECTR .GT. 3) GOTO 84
   83	IRET=IWRITW(256,DBUFF,IDBLK,IDCHAN)
	IDBLK=1
	GOTO 86
C
   84	IRET=IWRITW(512,DBUFF,IDBLK,IDCHAN)
	IDBLK=2
   86	IF (IRET .LT. 0) GOTO 95
   90	IF (IDBLK .EQ. 0) GOTO 94
	CALL ICLOSE(IDCHAN)
   92	CALL IFREEC(IDCHAN)
	RETURN
C
C  FILE OF 0 LENGTH, EAT IT.
   94	CALL PURGE(IDCHAN)
	GOTO 92
C
   95	TYPE *,'WRITE ERROR IN CPYFIL, TYPE ',IRET
	STOP
	END
C
	SUBROUTINE ERASE (CNAME,ICHAN,ISTAT)
C****************************************************
C*                                                  *
C*  ERASE CP/M FILE 'CNAME' VIA CHANNEL ICHAN.      *
C*   RET ISTAT=0 IF OK, ELSE -1.                    *
C*                                                  *
C*  RUSS BAKKE               12-07-82               *
C*                                                  *
C****************************************************
C
	BYTE DIR(32,64),CNAME(12)
	COMMON DIR
C
	CALL GETDIR(ICHAN)
	CALL FIND(CNAME,0,IENTRY)
	IF (IENTRY .EQ. -1) GOTO 50	!UNSUCCESSFUL
	IEXT=0
   10	DIR (1,IENTRY)="345		!SET EMPTY
	IEXT=IEXT+1
	CALL FIND(CNAME,IEXT,IENTRY)	!MORE EXTENTS?
	IF (IENTRY .NE. -1) GOTO 10	!YES
	ISTAT=0
	RETURN
C
   50	ISTAT=-1	!UNSUCCESSFUL
	RETURN
	END