.TITLE HEXIFY .SBTTL Stuart Hecht .LIBRARY /SYS$LIBRARY:STARLET/ .LIBRARY /SYS$LIBRARY:LIB/ .IDENT /1.0.00/ ;++ ;NOTE - This the "old" version, that uses 16-bit internal length fields ; rather than 32-bit ones. ;This will take a task file and turn it into hexidecimal strings ;-- .EXTRN LIB$GET_INPUT .EXTRN LIB$PUT_SCREEN .MCALL $FAB ; RMS calls .MCALL $RAB .MCALL $CLOSE .MCALL $CONNECT .MCALL $CREATE .MCALL $DISCONNECT .MCALL $READ .MCALL $OPEN .MCALL $PUT .MCALL $RAB_STORE .MCALL $FAB_STORE .SBTTL Definitions of symbols DWRLUN =1 ; Disk read LUN DWWLUN =5 ; Disk write LUN KNORMAL =0 ; No error EOF =-1 ; End of file error code LEFTBYTE=^O377*^O400 ; All one in left byte HEXOFFSET=7 ; Offset to get to 'A from '9+1 CR =13. ; Carriage return LF =10. ; Line feed ; 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 Data .PSECT $PLIT$,LONG 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$OFLN 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 Data DEFALT: .ASCIZ 'SYS$DISK:' ; System default. DEFALN =.-DEFALT ; Size of the default device. .EVEN .SBTTL Storage locations .PSECT $OWN$,LONG .ALIGN LONG MSGDSC: .BLKW 1 ; Data block for terminal output .BYTE DSC$K_DTYPE_T .BYTE DSC$K_CLASS_S ADDR: .ADDRESS ADDR INP_STR_D: ; Key string desciptor .BLKL 1 INP_BUF: .ADDRESS ADDR INP_STR_LEN: ; Key string length .BLKL 1 BUCOUNT: .BLKL 1 ; Number of character available in the ; buffer (returned from RMS) RDCOUNT: .BLKL 1 ; Number of characters read from buffer WTCOUNT: .BLKL 1 ; Number of characters written CHCOUNT: .BLKL 1 ; Number of characters written to buff. NULCOUNT: .BLKL 1 ; Number of nulls not yet written CHKSUM: .BLKL 1 ; Checksum for the line ADDRESS: .BLKL 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 Data structures .ALIGN LONG RDFAB:: $FAB DNA=DEFALT,DNS=DEFALN,FNA=INP.N,FNS=INP.L,LCH=DWRLUN,FAC=,SHR=GET .ALIGN LONG RDRAB:: $RAB FAB=RDFAB,RAC=SEQ ; Beginning of RAB block. .ALIGN LONG WTFAB:: $FAB DNA=DEFALT,DNS=DEFALN,FNA=OUT.N,FNS=OUT.L,LCH=DWWLUN,FAC=PUT,SHR=NIL,ORG=SEQ,RAT=CR,RFM=VAR .ALIGN LONG WTRAB:: $RAB FAB=WTFAB,RAC=SEQ ; Beginning of RAB block. .SBTTL Main line code .PSECT $CODE$,LONG,EXE .ALIGN LONG HEXIFY:: .WORD ^M ; For CALLS that is used from operating system NOINP: MOVAB M$FILN,R11 ; Get the input prompt address MOVL #L$FILN,R12 MOVAB INP.N,R10 ; Get address of input and length MOVL #INP.L,R1 ; JSB READ ; Read the input file name TSTL R0 ; See if we got anything BEQL NOINP ; If no input then try again MOVL R0,R5 ; Save length MOVAB M$OFLN,R11 ; Get the address of the prompt MOVL #L$OFLN,R12 MOVAB OUT.N,R10 ; Get address of output file name MOVL #OUT.L,R1 ; and length JSB READ ; Read the output file name MOVL R0,R3 ; Save length TSTL R3 ; See if we got any input BNEQ GOTFIL ; Yes so branch ; Here so use the default output file name MOVL R5,R0 ; Get the input file length back MOVAB INP.N,R2 ; Get input address MOVAB OUT.N,R3 ; Point at buffer CLRL R1 ; Clear the character count 2$: CMPB (R2),#^A/./ ; Check for an extension BEQL 10$ ; If an extension then ignore rest ; of line MOVB (R2)+,(R3)+ ; Move into the output file name INCW R1 ; Increment counter SOBGTR R0,2$ ; Branch until done 10$: MOVB #^A/./,(R3)+ ; Write the extension for output file MOVB #^A/H/,(R3)+ ; MOVB #^A/E/,(R3)+ ; MOVB #^A/X/,(R3)+ ; ADDW3 #4,R1,R3 ; Get final character count ;++ ;Open files ;-- GOTFIL: ;Create output file MOVAL WTFAB,R1 ; Put address of FAB into R1. $FAB_STORE FAB=R1,FNS=R3 ; Tell RMS file name length $CREATE #WTFAB ; Create the file JSB RMSERR ; Check for file error MOVAL WTRAB,R1 ; Put address of RAB into R1. $RAB_STORE RAB=R1,UBF=WTBUF,RBF=WTBUF,USZ=#512.,RSZ=#512. ; Put address of user buffer in RAB. $CONNECT #WTRAB ; Connect to record. JSB RMSERR ; Check for file error ;Open input file AGAINSAM: MOVAL RDFAB,R1 ; Put address of FAB into R1. $FAB_STORE FAB=R1,FNS=R5 ; Tell RMS file name length $OPEN #RDFAB ; Open the file JSB RMSERR ; Check for file error MOVAL RDRAB,R1 ; Put address of RAB into R1. $RAB_STORE RAB=R1,UBF=RDBUF,RBF=RDBUF,USZ=#512.,RSZ=#512. $CONNECT #RDRAB ; Connect to record. JSB RMSERR ; Check for file error ;++ ;Do the actual work ;-- MOVZWL #512.,RDCOUNT ; Initialize buffer pointers MOVZWL #512.,BUCOUNT ; CLRL WTCOUNT ; CLRL ADDRESS ; Initialize the address CLRL NULCOUNT ; Initialize the number of nulls MOVAL RDFAB,R5 ; Get the FAB address ;Get the Record format (FIX, VAR, ...) MOVZBL #PKRFM,R10 ; Set packet type to record format JSB HEADER ; Output the header MOVZBL FAB$B_RFM(R5),R10 JSB CVTH ; Put the record format code into buff INCL CHCOUNT ; Increment counter JSB PUTLIN ; Write the line out ;Get the record type (CR, ...) MOVZBL #PKRAT,R10 ; Set packet type to record type JSB HEADER ; Output the header MOVZBL FAB$B_RAT(R5),R10 JSB CVTH ; Put the record type into buffer INCL CHCOUNT ; Increment counter JSB PUTLIN ; Write the line out ;Get the maximum record size (512. for tasks) MOVZBL #PKMRS,R10 ; Set packet type to max record size JSB HEADER ; Output the header MOVZWL FAB$W_MRS(R5),R10 PUSHL R10 ; Save for low order EXTZV #8.,#8.,R10,R10 ; Get high order byte JSB CVTH ; Put the record size into buffer INCL CHCOUNT ; Increment counter POPL R10 ; Get size back JSB CVTH ; Put the record size into buffer INCL CHCOUNT ; Increment counter JSB PUTLIN ; Write the line out ;Get the file length (in blocks) MOVZWL #PKALQ,R10 ; Set packet type to file length JSB HEADER ; Output the header MOVL FAB$L_ALQ(R5),R10 PUSHL R10 ; Save for low order EXTZV #8.,#8.,R10,R10 ; Get high order byte JSB CVTH ; Put the allocation into buffer INCL CHCOUNT ; Increment counter POPL R10 ; Get allocation back JSB CVTH ; Put the low order into the buffer INCL CHCOUNT ; Increment counter JSB PUTLIN ; Write the line out ;Get the file name MOVZBL #PKFILNM,R10 ; Set packet type to file name JSB HEADER ; Output the header MOVZBL FAB$B_FNS(R5),R4 MOVAB INP.N,R3 ; Get the input file name address 25$: MOVZBL (R3)+,R10 ; Get the next character JSB CVTH ; Buffer the next character of the name INCL CHCOUNT ; Increment counter SOBGTR R4,25$ ; Repeat until all done JSB PUTLIN ; Write the line out ;++ ; Start moving real data ;-- NEXLIN: JSB GET ; Get a character from the buffer CMPL R10,#EOF ; Check for end of file BEQL FINISH ; If at end the finish up TSTL R10 ; Check for null character BNEQ DOLIN ; Not null so just do regular stuff INCL ADDRESS ; Point to next location BRB NEXLIN ; save space and try again DOLIN: PUSHL R10 ; Save the character we have MOVZWL #PKDATA,R10 ; Set packet type to plain old data JSB HEADER ; Put the standard header into buffer POPL R10 ; Get the original character back LINAGA: JSB CVTHEX ; Convert the character to hex codes INCL ADDRESS ; Point to next location INCL CHCOUNT ; Increment the character count CMPL CHCOUNT,#^O36 ; Check to see if we should finish BNEQ LINMOR ; this line JSB PUTLIN ; Put the whole line to disk BRW NEXLIN ; Go do the next line LINMOR: JSB GET ; Get the next character CMPL R10,#EOF ; Is it an end of file? BNEQ LINAGA ; No, then just handle normally ; JSB PUTLIN ; Yes, write the current line DECL ADDRESS ; Reset address to correct value BRW FIN1 ; Finish up .SBTTL Finish up ;++ ;Finish up ;-- FINISH: MOVZBL #PKDATA,R10 ; Set packet type to plain old data JSB HEADER ; Insert the header so the extra ; nulls are seen FIN1: TSTL NULCOUNT ; See if no nulls left BEQL FIN ; If none then branch CLRL R10 ; Get a null DECL NULCOUNT ; Decrement the counter JSB CVTH ; Convert to HEX (w/o null compression) FIN: JSB PUTLIN ; Put the current buffer to disk ; Write out the end of task file line CLRL CHCOUNT ; Clear character count MOVZBL #PKEOF,R10 ; Get end of task file packet type JSB HEADER ; Make the header JSB PUTLIN ; Write the line ; Close the input (task) file MOVAL RDFAB,R1 ; Get the FAB for input file $CLOSE R1 ; Close input file JSB RMSERR ; Check for file error ; See about another file to append MOVAB M$NEXF,R11 ; See if another file should be MOVL #L$NEXF,R12 ; appended to the HEX file MOVAB INP.N,R10 ; MOVL #INP.L,R1 ; Get address of input and length JSB READ ; Read the input file name TSTL R0 ; See if we got anything BEQL LEAVE ; If no input then leave MOVL 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: CLRL CHKSUM ; Clear the checksum for this line CLRL CHCOUNT ; Clear character count MOVZBL #^A/:/,R10 ; Get the start character JSB BUFFER ; Put it into the buffer MOVZBL #8.,R5 ; Get the number of nulls needed FINREP: MOVZBL #^A/0/,R10 ; Set the character to 'null' JSB BUFFER ; Put it into the buffer SOBGTR R5,FINREP ; Repeat if not done JSB PUTLIN ; Write the buffer to disk ; Close the HEX file MOVAL WTFAB,R1 ; Get FAB for output file $CLOSE R1 ; Close output file JSB RMSERR ; Check for file error END: MOVL #SS$_NORMAL,R0 ; Set up successful completion RET ; Exit program .SBTTL Put a data line ;++ ;Finish a line up by inserting the length and the checksum and doing a PUT ;-- PUTLIN: MOVL CHCOUNT,R10 ; Get the actual character count SUBL2 NULCOUNT,R10 ; Don't include the nulls since we ; won't write them CLRL NULCOUNT ; Clear the null count since the ; address will serve to insert nulls PUSHL WTCOUNT ; Save it on the stack MOVZBL #1,WTCOUNT ; Move a one into the char count to get JSB CVTH ; to the length and then put length in POPL WTCOUNT ; Restore the correct count MNEGL CHKSUM,R10 ; Negate it JSB CVTH ; Put the negative checksum into buffer JSB PUT ; Put the line to disk RSB ; Return to sender .SBTTL Create the header for the data line ;++ ;This routine will put the starting stuff into the buffer ;R10 contains the record type ;-- HEADER: CLRL CHKSUM ; Clear the checksum for this line CLRL CHCOUNT ; Clear character count PUSHL R10 ; Save the record type MOVZBL #^A/:/,R10 ; Move a colon into first char position JSB BUFFER ; of the buffer CLRL R10 ; Move a fake length into the buffer JSB CVTH ; MOVZBL ADDRESS+3,R10 ; Get the 4th byte of the JSB CVTH ; address and put into the buffer MOVZBL ADDRESS+2,R10 ; Get the 3rd byte of the JSB CVTH ; address and put into the buffer MOVZBL ADDRESS+1,R10 ; Get the 2nd byte of the JSB CVTH ; address and put into the buffer MOVZBL ADDRESS,R10 ; Get the 1rst byte of address and JSB CVTH ; buffer it POPL R10 ; Get the line record type JSB CVTH ; and buffer the code RSB ; Return to sender .SBTTL Output and input to/from terminal ;++ ; Write data to terminal. ; R10 Address of data to output ; R1 Length of data ;-- WRITE: MOVW R1,MSGDSC ; Store the length in the descript blk MOVL R10,ADDR ; Store the address of the ASCII PUSHAQ MSGDSC ; Push the descriptor block address CALLS #1,G^LIB$PUT_OUTPUT ; Do the output RSB ; Return to sender ;++ ; Read from the terminal ; R10 Address of buffer ; R1 Number of characters to read ; R11 Input prompt address ; R12 Length of prompt ; ;Returned: ; R0 Number of characters read ;-- READ: MOVL R1,INP_STR_D ; Store the buffer length in desc block MOVL R10,INP_BUF ; Store the buffer address in desc blk MOVL R11,ADDR ; Store prompt address in desc block MOVW R12,MSGDSC ; Store length in desctriptor block PUSHAB INP_STR_LEN ; Address for string length PUSHAQ MSGDSC ; Push address of prompt descriptor blk PUSHAB INP_STR_D ; String buffer descriptor CALLS #3,G^LIB$GET_INPUT ; Get input string value MOVL INP_STR_LEN,R0 ; Get actual input length back RSB ; Return to sender .SBTTL RMS error routine ;++ ;Check for RMS error ;-- RMSERR: BLBC R0,60$ ; If error, go check it out MOVL #KNORMAL,R0 ; Set up a successful return code. RSB ; Return to caller ; Here if there is an error 60$: CMPL #RMS$_EOF,R0 ; Check for EOF BNEQ 70$ ; If not then branch MOVL #EOF,R0 ; Tell sender we have end of file RSB ; Return ; Here if there is an RMS error we don't know how to handle 70$: PUSHL R0 ; Save the error code MOVAB M$RMS,R10 ; Get the address and length of the MOVL #L$RMS,R1 ; message to output JSB WRITE ; Output it POPL R0 ; Get the error code back RET ; Exit program .SBTTL Get a character from the file ;++ ;Get a character from the input file. ; ; Returned: ; R10 Contains the character if not at end of file ; Contains #EOF if at end of file ;-- GET: MOVL RDCOUNT,R10 ; Get the offset into the buffer CMPL R10,BUCOUNT ; Check to see if we are past the end BNEQ 10$ ; If not then branch MOVAL RDRAB,R1 ; Get the RAB address $RAB_STORE RAB=R1,UBF=RDBUF,USZ=#512. $READ R1 ; Get the next buffer of data. JSB RMSERR ; Check for file error CMPL R0,#EOF ; Check for end of file error BNEQ 5$ ; If not then branch MOVL R0,R10 ; Move the status to the correct spot RSB ; Return with error code 5$: MOVZWL RAB$W_RSZ+RDRAB,R10 MOVL R10,BUCOUNT ; Save the record size CLRL R10 ; Clear the pointer CLRL RDCOUNT ; . . . 10$: MOVZBL RDBUF(R10),R10 ; Get the next character INCL RDCOUNT ; Increment the offset into the buffer RSB ; Return to sender .SBTTL Buffer a character of the data line ;++ ; Buffer the character in R10 ;-- BUFFER: PUSHL R10 ; Save the character on the stack MOVL WTCOUNT,R10 ; Get the offset into the buffer CMPL #512.,R10 ; Get too big? BGTR BUFOK NOP BUFOK: MOVB (SP),WTBUF(R10) ; Move the character to the buffer TSTL (SP)+ ; Remove the junk INCL WTCOUNT ; Increment the pointer BUFRTS: RSB ; Return to sender .SBTTL Put a record to the file ;++ ;Write the record ;-- PUT: MOVL WTCOUNT,R10 ; Get the count MOVAL WTRAB,R1 ; Get the RAB address $RAB_STORE RAB=R1,RSZ=R10 $PUT R1 ; Output the record JSB RMSERR ; Check for file error CLRL WTCOUNT ; Clear the counter for next record RSB ; Return .SBTTL Convert to Hexadecimal ASCII digits ;++ ; Convert a word to 2 ASCII hexadecimal digits ;-- CVTHEX: TSTL R10 ; See if this is a null BNEQ CVTH ; If not then just branch INCL NULCOUNT ; A null so just increment the count RSB ; for later and leave ; Convert a word to 2 ASCII hexadecimal digits without null compression CVTH: PUSHL R10 ; Save the character on the stack 10$: TSTL NULCOUNT ; Check to see if there are nulls BEQL 20$ ; If not then just branch CLRL R10 ; Put a null in R10 JSB CVT1 ; Put the null in the buffer DECL NULCOUNT ; Decrement null counter BRB 10$ ; Repeat 20$: POPL R10 ; Get the original value back CVT1: ADDL2 R10,CHKSUM ; Add the value to the checksum MOVL R10,R1 ; Save the value EXTZV #4,#4,R10,R10 ; Get high order digit JSB HEX ; in place and convert to Hex JSB BUFFER ; Buffer the Hex character EXTZV #0,#4,R1,R10 ; Get right digit JSB HEX ; Convert to Hex JSB BUFFER ; Buffer the Hex character RSB ; Return to sender HEX: MOVL R10,R2 ; Move the base to R2 CMPL R2,#9. ; Check to see if above '9 BLEQ 1$ ; If not then branch ADDL2 #HEXOFFSET,R10 ; Add offset to alphabet 1$: ADDL2 #48.,R10 ; Make ASCII RSB ; Return to sender .SBTTL End of Hexify .END HEXIFY