.TITLE HEXIFY .SBTTL Stuart Hecht .LIBRARY /LB:[1,5]RMSMAC/ .ENABLE LC .NLIST BEX .IDENT /1.0.00/ ;++ ;This will take a task file and turn it into hexidecimal strings ;-- .MCALL QIOW$S,QIOW$,ALUN$S,EXIT$S .MCALL FAB$B ; RMS calls .MCALL RAB$B .MCALL $CLOSE .MCALL $CONNECT .MCALL $CREATE .MCALL $DISCONNECT .MCALL $READ .MCALL $OPEN .MCALL $FETCH .MCALL $PUT .MCALL $STORE .MCALL $SET .MCALL ORG$ .MCALL POOL$B .SBTTL Definitions of symbols TERLUN =7 ; Terminal LUN TTEFN =1 ; Terminal Event Flag DWRLUN =1 ; Disk read LUN DWWLUN =5 ; Disk write LUN TRUE =1 ; True FALSE =0 ; False KNORMAL =0 ; No error RMS11 =1 ; RMS error EOF =-1 ; End of file error code LEFTBYTE=377*400 ; All one in left byte HEXOFFSET=7 ; Offset to get to 'A from '9+1 ; Packet types currently created PKDATA =0 ; Data packet code PKRFM =255. ; Record format PKRAT =254. ; Record attributes PKMRS =253. ; Maximum record size PKALQ =252. ; File length(blocks) PKFILNM =251. ; File name PKEOF =250. ; End of file ; .SBTTL RMS Initialization POOL$B ; Allocate static pool for RMS P$RAB 5 ; For internal RABs P$BDB 5 ; For buffer descriptor blocks P$FAB 4 ; For internal FABs P$BUF 2048. ; Buffer space POOL$E ; End of pool declarations ORG$ SEQ ; $Open a sequential file .SBTTL Data .PSECT $PLIT$,RO,D M$FILN: .BYTE CR,LF,LF .ASCII 'Input file name: ' L$FILN =.-M$FILN M$OFLN: .BYTE CR,LF,LF .ASCII 'Output file name (or return for the default): ' L$OFLN =.-M$OFLNM M$NEXF: .BYTE CR,LF,LF .ASCII 'Press return to finish or type the name of another file' .BYTE CR,LF .ASCII 'to append to the HEX file: ' L$NEXF =.-M$NEXF M$RMS: .BYTE CR,LF,LF .ASCII 'RMS ERROR' L$RMS =.-M$RMS .EVEN .SBTTL RMS 11 Data DEFALT: .ASCIZ 'SY:' ; System default. DEFALN =.-DEFALT ; Size of the default device. .EVEN .SBTTL Storage locations .PSECT $OWN$ IOSTAT: .BLKW 1 ; QIO status STAT1: .BLKW 1 ; Second word of status BUCOUNT: .BLKW 1 ; Number of character available in the ; buffer (returned from RMS) RDCOUNT: .BLKW 1 ; Number of characters read from buffer WTCOUNT: .BLKW 1 ; Number of characters written CHCOUNT: .BLKW 1 ; Number of characters written to buff. NULCOUNT: .BLKW 1 ; Number of nulls not yet written CHKSUM: .BLKW 1 ; Checksum for the line ADDRESS: .BLKW 1 ; Current address INP.N: .BLKB 28. ; Space for input file name INP.L =.-INP.N ; Length of input file name OUT.N: .BLKB 28. ; Space for output file name OUT.L =.-OUT.N ; Length of input file name RDBUF: .BLKB 512. ; Disk read buffer WTBUF: .BLKB 512. ; Disk write buffer .EVEN .SBTTL RMS 11 Data structures RDFAB:: FAB$B F$DNA DEFALT ; Address of default device. F$DNS DEFALN ; Default length field. F$FNA INP.N ; Address of file name F$FNS INP.L ; Length of file name F$LCH DWRLUN ; Logical channel to use FAB$E .EVEN RDRAB:: RAB$B ; Beginning of RAB block. R$FAB RDFAB ; Chain to FAB block. R$RAC RB$SEQ ; Set the sequential access flag. RAB$E ; End RAB block. .EVEN WTFAB:: FAB$B F$DNA DEFALT ; Address of default device. F$DNS DEFALN ; Default length field. F$FNA OUT.N ; Address of file name F$FNS OUT.L ; Length of file name F$LCH DWWLUN ; Logical channel to use FAB$E .EVEN WTRAB:: RAB$B ; Beginning of RAB block. R$FAB WTFAB ; Chain to FAB block. R$RAC RB$SEQ ; Set the sequential access flag. RAB$E ; End RAB block. .EVEN .SBTTL Main line code .PSECT $CODE$,RO,I HEXIFY:: ALUN$S #TERLUN,#"TI,#0 ; Assign terminal LUN NOINP: MOV #M$FILN,R0 ; Get the address and length of the MOV #L$FILN,R1 ; message to output JSR PC,WRITE ; Output it MOV #INP.N,R0 ; Get address of input and length MOV #INP.L,R1 ; JSR PC,READ ; Read the input file name TST R0 ; See if we got anything BEQ NOINP ; If no input then try again MOV R0,R5 ; Save length MOV #M$OFLN,R0 ; Get the address and length of the MOV #L$OFLN,R1 ; message to output JSR PC,WRITE ; Output it MOV #OUT.N,R0 ; Get address of output file name MOV #OUT.L,R1 ; and length JSR PC,READ ; Read the output file name MOV R0,R3 ; Save length TST R3 ; See if we got any input BNE GOTFIL ; Yes so branch ; Here so use the default output file name MOV R5,R0 ; Get the input file length back MOV #INP.N,R2 ; Get input address MOV #OUT.N,R3 ; Point at buffer 2$: CMPB (R2),#'. ; Check for an extension BEQ 10$ ; If an extension then ignore rest ; of line MOVB (R2)+,(R3)+ ; Move into the output file name SOB R0,2$ ; Branch until done 10$: MOVB #'.,(R3)+ ; Write the extension for output file MOVB #'H,(R3)+ ; MOVB #'E,(R3)+ ; MOVB #'X,(R3)+ ; SUB #OUT.N,R3 ; Make final count ;++ ;Open files ;-- GOTFIL: ;Create output file MOV #WTFAB,R1 ; Put address of FAB into R1. $SET #FB$CR,RAT,R1 ; Set the record handling mask. $STORE R3,FNS,R1 ; Tell RMS file name length $CREATE #WTFAB ; Create the file JSR PC,RMSERR ; Check for file error MOV #WTRAB,R1 ; Put address of RAB into R1. $STORE #WTBUF,UBF,R1 ; Put address of user buffer in RAB. $STORE #WTBUF,RBF,R1 ; Put record buffer address in RAB $STORE #512.,USZ,R1 ; Put size of user buffer into RAB. $STORE #512.,RSZ,R1 ; Put record buffer size in RAB $CONNECT #WTRAB ; Connect to record. JSR PC,RMSERR ; Check for file error ;Open input file AGAINSAM: MOV #RDFAB,R1 ; Put address of FAB into R1. $SET #FB$REA,FAC,R1 ; Set the block read in FAB. $STORE R5,FNS,R1 ; Tell RMS file name length $OPEN #RDFAB ; Open the file JSR PC,RMSERR ; Check for file error MOV #RDRAB,R1 ; Put address of RAB into R1. $STORE #RDBUF,UBF,R1 ; Put address of user buffer in RAB. $STORE #RDBUF,RBF,R1 ; Put record buffer address in RAB $STORE #512.,USZ,R1 ; Put size of user buffer into RAB. $STORE #512.,RSZ,R1 ; Put record buffer size in RAB $CONNECT #RDRAB ; Connect to record. JSR PC,RMSERR ; Check for file error ;++ ;Do the actual work ;-- MOV #512.,RDCOUNT ; Initialize buffer pointers MOV #512.,BUCOUNT ; CLR WTCOUNT ; CLR ADDRESS ; Initialize the address CLR NULCOUNT ; Initialize the number of nulls MOV #RDFAB,R5 ; Get the FAB address ;Get the Record format (FIX, VAR, ...) MOV #PKRFM,R0 ; Set packet type to record format JSR PC,HEADER ; Output the header $FETCH R0,RFM,R5 ; Get the record format JSR PC,CVTH ; Put the record format code into buff INC CHCOUNT ; Increment counter JSR PC,PUTLIN ; Write the line out ;Get the record type (CR, ...) MOV #PKRAT,R0 ; Set packet type to record type JSR PC,HEADER ; Output the header $FETCH R0,RAT,R5 ; Get the record type JSR PC,CVTH ; Put the record type into buffer INC CHCOUNT ; Increment counter JSR PC,PUTLIN ; Write the line out ;Get the maximum record size (512. for tasks) MOV #PKMRS,R0 ; Set packet type to max record size JSR PC,HEADER ; Output the header $FETCH R0,MRS,R5 ; Get the maximum record size MOV R0,-(SP) ; Save for low order SWAB R0 ; Get high order byte JSR PC,CVTH ; Put the record size into buffer INC CHCOUNT ; Increment counter MOV (SP)+,R0 ; Get size back JSR PC,CVTH ; Put the record size into buffer INC CHCOUNT ; Increment counter JSR PC,PUTLIN ; Write the line out ;Get the file length (in blocks) MOV #PKALQ,R0 ; Set packet type to file length JSR PC,HEADER ; Output the header $FETCH R0,ALQ,R5 ; Get the allocation MOV R0,-(SP) ; Save for low order SWAB R0 ; Get high order byte JSR PC,CVTH ; Put the allocation into buffer INC CHCOUNT ; Increment counter MOV (SP)+,R0 ; Get allocation back JSR PC,CVTH ; Put the low order into the buffer INC CHCOUNT ; Increment counter JSR PC,PUTLIN ; Write the line out ;Get the file name MOV #PKFILNM,R0 ; Set packet type to file name JSR PC,HEADER ; Output the header $FETCH R4,FNS,R5 ; Get the file name length MOV #INP.N,R3 ; Get the input file name address 25$: MOVB (R3)+,R0 ; Get the next character JSR PC,CVTH ; Buffer the next character of the name INC CHCOUNT ; Increment counter SOB R4,25$ ; Repeat until all done JSR PC,PUTLIN ; Write the line out ;++ ; Start moving real data ;-- NEXLIN: JSR PC,GET ; Get a character from the buffer CMP R0,#EOF ; Check for end of file BEQ FINISH ; If at end the finish up TST R0 ; Check for null character BNE DOLIN ; Not null so just do regular stuff INC ADDRESS ; Point to next location BR NEXLIN ; save space and try again DOLIN: MOV R0,-(SP) ; Save the character we have MOV #PKDATA,R0 ; Set packet type to plain old data JSR PC,HEADER ; Put the standard header into buffer MOV (SP)+,R0 ; Get the original character back LINAGA: JSR PC,CVTHEX ; Convert the character to hex codes INC ADDRESS ; Point to next location INC CHCOUNT ; Increment the character count CMP CHCOUNT,#36 ; Check to see if we should finish BNE LINMOR ; this line JSR PC,PUTLIN ; Put the whole line to disk BR NEXLIN ; Go do the next line LINMOR: JSR PC,GET ; Get the next character CMP R0,#EOF ; Is it an end of file? BNE LINAGA ; No, then just handle normally ; JSR PC,PUTLIN ; Yes, write the current line DEC ADDRESS ; Reset address to correct value BR FIN1 ; Finish up .SBTTL Finish up ;++ ;Finish up ;-- FINISH: MOV #PKDATA,R0 ; Set packet type to plain old data JSR PC,HEADER ; Insert the header so the extra ; nulls are seen FIN1: TST NULCOUNT ; See if no nulls left BEQ FIN ; If none then branch CLR R0 ; Get a null DEC NULCOUNT ; Decrement the counter JSR PC,CVTH ; Convert to HEX (w/o null compression) FIN: JSR PC,PUTLIN ; Put the current buffer to disk ; Write out the end of task file line CLR CHCOUNT ; Clear character count MOV #PKEOF,R0 ; Get end of task file packet type JSR PC,HEADER ; Make the header JSR PC,PUTLIN ; Write the line ; Close the input (task) file MOV #RDFAB,R1 ; Get the FAB for input file $CLOSE R1 ; Close input file JSR PC,RMSERR ; Check for file error ; See about another file to append MOV #M$NEXF,R0 ; See if another file should be MOV #L$NEXF,R1 ; appended to the HEX file JSR PC,WRITE ; MOV #INP.N,R0 ; Get address of input and length MOV #INP.L,R1 ; JSR PC,READ ; Read the input file name TST R0 ; See if we got anything BEQ LEAVE ; If no input then leave MOV R0,R5 ; Put the length in R5 for the open JMP AGAINSAM ; Repeat process for this file ; Write out end of hex file line LEAVE: CLR CHKSUM ; Clear the checksum for this line CLR CHCOUNT ; Clear character count MOV #':,R0 ; Get the start character JSR PC,BUFFER ; Put it into the buffer MOV #8.,R5 ; Get the number of nulls needed FINREP: MOV #'0,R0 ; Set the character to 'null' JSR PC,BUFFER ; Put it into the buffer SOB R5,FINREP ; Repeat if not done JSR PC,PUTLIN ; Write the buffer to disk ; Close the HEX file MOV #WTFAB,R1 ; Get FAB for output file $CLOSE R1 ; Close output file JSR PC,RMSERR ; Check for file error END: EXIT$S .SBTTL Put a data line ;++ ;Finish a line up by inserting the length and the checksum and doing a PUT ;-- PUTLIN: MOV CHCOUNT,R0 ; Get the actual character count SUB NULCOUNT,R0 ; Don't include the nulls since we ; won't write them CLR NULCOUNT ; Clear the null count since the ; address will serve to insert nulls MOV WTCOUNT,-(SP) ; Save it on the stack MOV #1,WTCOUNT ; Move a one into the char count to get JSR PC,CVTH ; to the length and then put length in MOV (SP)+,WTCOUNT ; Restore the correct count MOV CHKSUM,R0 ; Get the checksum NEG R0 ; Negate it JSR PC,CVTH ; Put the negative checksum into buffer JSR PC,PUT ; Put the line to disk RTS PC ; Return to sender .SBTTL Create the header for the data line ;++ ;This routine will put the starting stuff into the buffer ;R0 contains the record type ;-- HEADER: CLR CHKSUM ; Clear the checksum for this line CLR CHCOUNT ; Clear character count MOV R0,-(SP) ; Save the record type MOV #':,R0 ; Move a colon into first char position JSR PC,BUFFER ; of the buffer CLR R0 ; Move a fake length into the buffer JSR PC,CVTH ; MOVB ADDRESS+1,R0 ; Get the high order word of the JSR PC,CVTH ; address and put into the buffer MOVB ADDRESS,R0 ; Get low order word of address and JSR PC,CVTH ; buffer it MOV (SP)+,R0 ; Get the line record type JSR PC,CVTH ; and buffer the code RTS PC ; Return to sender .SBTTL Output and input to/from terminal ;++ ; Write data to terminal. ; R0 Address of data to output ; R1 Length of data ;-- WRITE: QIOW$S #IO.WVB,#TERLUN,#TTEFN,,#IOSTAT,, RTS PC ;++ ; Read from the terminal ; R0 Address of buffer ; R1 Number of characters to read ; ;Returned: ; R0 Number of characters read ;-- READ: QIOW$S #IO.RVB!TF.ESQ,#TERLUN,#TTEFN,,#IOSTAT,, MOV STAT1,R0 ; Get the number of character read RTS PC .SBTTL RMS error routine ;++ ;Check for RMS error ;-- RMSERR: $FETCH R0,STS,R1 ; Get the status and put it in R0 TST R0 ; Test the status code for success. BMI 60$ ; If negative then branch. MOV #KNORMAL,R0 ; Set up a successful return code. RTS PC ; Return to caller ; Here if there is an error 60$: CMP #ER$EOF,R0 ; Check for EOF BNE 70$ ; If not then branch MOV #EOF,R0 ; Tell sender we have end of file RTS PC ; Return ; Here if there is an RMS error we don't know how to handle 70$: MOV #M$RMS,R0 ; Get the address and length of the MOV #L$RMS,R1 ; message to output JSR PC,WRITE ; Output it EXIT$S ; Exit since we can't finish .SBTTL Get a character from the file ;++ ;Get a character from the input file. ; ; Returned: ; R0 Contains the character if not at end of file ; Contains #EOF if at end of file ;-- GET: MOV RDCOUNT,R0 ; Get the offset into the buffer CMP R0,BUCOUNT ; Check to see if we are past the end BNE 10$ ; If not then branch MOV #RDRAB,R1 ; Get the RAB address $READ R1 ; Get the next buffer of data. JSR PC,RMSERR ; Check for file error CMP R0,#EOF ; Check for end of file error BNE 5$ ; If not then branch RTS PC ; Return with error code 5$: $FETCH R0,RSZ,R1 ; Get the record size and put it in R0 MOV R0,BUCOUNT ; Save the record size CLR R0 ; Clear the pointer CLR RDCOUNT ; . . . 10$: MOVB RDBUF(R0),R0 ; Get the next character INC RDCOUNT ; Increment the offset into the buffer BIC #LEFTBYTE,R0 ; Clear high order byte of R0 RTS PC ; Return to sender .SBTTL Buffer a character of the data line ;++ ; Buffer the character in R0 ;-- BUFFER: MOV R0,-(SP) ; Save the character on the stack MOV WTCOUNT,R0 ; Get the offset into the buffer MOVB (SP)+,WTBUF(R0) ; Move the character to the buffer INC WTCOUNT ; Increment the pointer BUFRTS: RTS PC ; Return to sender .SBTTL Put a record to the file ;++ ;Write the record ;-- PUT: MOV WTCOUNT,R0 ; Get the count MOV #WTRAB,R1 ; Get the RAB address $STORE R0,RSZ,R1 ; Put its size into the RAB. $PUT R1 ; Output the record JSR PC,RMSERR ; Check for file error CLR WTCOUNT ; Clear the counter for next record RTS PC ; Return .SBTTL Convert to Hexadecimal ASCII digits ;++ ; Convert a word to 2 ASCII hexadecimal digits ;-- CVTHEX: TST R0 ; See if this is a null BNE CVTH ; If not then just branch INC NULCOUNT ; A null so just increment the count RTS PC ; for later and leave ; Convert a word to 2 ASCII hexadecimal digits without null compression CVTH: MOV R0,-(SP) ; Save the character on the stack 10$: TST NULCOUNT ; Check to see if there are nulls BEQ 20$ ; If not then just branch CLR R0 ; Put a null in R0 JSR PC,CVT1 ; Put the null in the buffer DEC NULCOUNT ; Decrement null counter BR 10$ ; Repeat 20$: MOV (SP)+,R0 ; Get the original value back CVT1: ADD R0,CHKSUM ; Add the value to the checksum MOV R0,R1 ; Save the value BIC #17+LEFTBYTE,R0 ; Leave only left Hex digit ASH #-4,R0 ; Shift right to get first digit JSR PC,HEX ; in place and convert to Hex JSR PC,BUFFER ; Buffer the Hex character MOV R1,R0 ; Get the original value back BIC #17*20+LEFTBYTE,R0 ; Get right Hex digit JSR PC,HEX ; Convert to Hex JSR PC,BUFFER ; Buffer the Hex character RTS PC ; Return to sender HEX: MOV R0,R2 ; Move the base to R2 CMP R2,#9. ; Check to see if above '9 BLE 1$ ; If not then branch ADD #HEXOFFSET,R0 ; Add offset to alphabet 1$: ADD #48.,R0 ; Make ASCII RTS PC ; Return to sender .SBTTL End of Hexify .END HEXIFY