.TITLE MISH - Mish files .IDENT /1.1/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided or ; otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: MISH.MAC ; Author: Robin Miller & Gary Larsen ; Date: November 11, 1982 ; ; Description: ; ; This program is used to analyze, compress, and decompress files of ; any format into a variable length file with 80 bytes records. This program ; is primarily used to convert 512 byte fixed length record files into ASCII ; text files with 80 byte records. ; ; Modification History: ; ; May 10, 1984 by Robin Miller ; Require an input file name. Append .MIS extension to the output ; file name when an output file isn't specified. ; ;- .ENABL AMA .NLIST BEX .MCALL ALUN$S, DIR$, EXIT$S, EXST$S, GTSK$, QIOW$, QIOW$S .MCALL GCMLB$, GCML$, FDAT$A, FDRC$A, FDOP$A, FDBF$A .MCALL CLOSE$, FINIT$, FSRSZ$, FDBDF$, NMBLK$, READ$, WAIT$ ; Local equates: DEPTH = 2 ; Depth of command files. ; ASCII Messages: PRADR: .ASCII "MISH>" PRLEN = .-PRADR .EVEN .SBTTL Status Bit Definitions ; Status bit definitions: B.CMNT == 1 ; Comment line. B.IFIL == 2 ; Input file specified. B.OFIL == 4 ; Output file specified. B.TOT == 10 ; Output total blocks and records. B.HDR == 20 ; Analyze; output header record. B.HEX == 40 ; Analyze; dump SCB in hexadecimal. B.OCT == 100 ; Analyze; dump SCB in octal. B.REV == 200 ; Analyze; put SCB in reverse video. B.DATA == 400 ; Analyze; output data in each record. ; == 1000 ; ; == 2000 ; ; == 4000 ; ; == 10000 ; ; == 20000 ; ; == 40000 ; B.CTRC == 100000 ; Control/C was typed to abort. STATUS::.WORD 0 ; Status word for options. ; Offsets for argument block: O.RADR == 2 ; Address of the input record. O.RLEN == 4 ; Address of the record byte count. O.BADR == 6 ; Address of the transmit buffer. O.BLEN == 10 ; Address of the transmit byte count. O.MAX == 12 ; Address of the maximum transmit bc. O.STAT == 14 ; Address to return the status. ; Argument block for compress routine. ARGBLK::.BYTE 6,0 ; Argument count. .WORD RECADR ; Address of the input record. .WORD RECLEN ; Address of record length. .WORD BUFADR ; Address of the transmit buffer. .WORD BUFLEN ; Address of transmit length. .WORD MAXSIZ ; Address of maximum size of buffer. .WORD ASTAT ; Address for return status. ; Storage area for above: RECADR::.BLKB BLKSIZ ; Storage for input record. RECLEN::.WORD 0 ; The input record length. BUFADR::.BLKB BLKSIZ*2 ; Storage for the transmit buffer. BUFLEN::.WORD 0 ; Current transmit buffer length. WRKBUF::.BLKB BLKSIZ*2 ; Storage for converted text WRKLEN::.WORD BLKSIZ*2 ; Length for work buffer MAXSIZ::.WORD BUFEND ; Maximum size of transmit buffer. ASTAT:: .WORD 0 ; Return status goes here. ; Get Command Line control block. GCLBLK::GCMLB$ DEPTH,,CMDBUF,TILUN,,CMDSIZ ATTACH: QIOW$ IO.ATA,TOLUN,TOEFN,,TIOSB,,<,,CTRLC> GETTSK: GTSK$ TSKBUF ; Get task parameters TSKBUF: .BLKW 16. ; and the buffer. VAXFLG::.WORD 0 ; Running on VAX/VMS -1 = TRUE ; Storage area: TIOSB:: .BLKW 2 ; Terminal I/O status block. ISTAT:: .BLKW 2 ; Input file I/O status block. OSTAT:: .BLKW 2 ; Output file I/O status block. IVBN:: .BLKW 2 ; Input file virtual block number. OVBN:: .BLKW 2 ; Output file virtual block number. SFFBY:: .WORD 0 ; Save area for First Free Byte. STBLK:: .BLKW 5 ; Buffer for file statistics block. FIELDW::.WORD 0 ; Width of field for anaylze dump. ATRFLG::.WORD 0 ; Attributes on flag 0/-1 = no/yes. TYPOPR::.WORD 0 ; Type of operation -2/0/2 = A/C/D. SCBADR::.WORD 0 ; Address of the string control byte. SCBCNT::.WORD 0 ; The data count for this SCB. RECNUM::.WORD 0 ; Number of records. BLKNUM::.WORD 0 ; Number of blocks. ORGLEN::.WORD 0 ; Original record/buffer length. COMLEN::.WORD 0 ; Compressed record/buffer length. INPTR:: .WORD INFIL ; Pointer to the input file name. OUTPTR::.WORD OUTFIL ; Pointer to the output file name. CMDBUF::.BLKB CMDSIZ ; Command file input buffer. ERRBUF::.BLKB ERRSIZ ; Storage for error messages. FMTBUF::.BLKB RECSIZ*2 ; Storage for format buffer. INFIL:: .BLKB FILSIZ ; Storage for input file name. .BYTE 377 ; Used to flag end of buffer. .EVEN OUTFIL::.BLKB FILSIZ ; Storage for output file name. .BYTE 377 ; Used to flag end of buffer. .EVEN ; File Storage Region and File Descriptor Block Allocation. FSRSZ$ 5 ; FSR space for 5 open files. TIFDB:: FDBDF$ ; FDB for terminal input. FDAT$A R.VAR,FD.CR,,, ; Variable length / implied. FDRC$A ,CMDBUF,CMDSIZ ; Locate mode / max size. FDOP$A TILUN,,DEFNB,FO.RD ; Open for read access. FDBF$A TIEFN,CMDSIZ,, ; Init block buffer section. TOFDB:: FDBDF$ ; FDB for terminal output. FDAT$A R.VAR,FD.CR,,, ; Variable length / implied. FDRC$A ,FMTBUF,RECSIZ ; Locate mode / max size. FDOP$A TOLUN,,OUTNB,FO.WRT ; Open for write access. FDBF$A TOEFN,RECSIZ,, ; Init block buffer section ERRFDB::FDBDF$ ; FDB for error messages. FDAT$A R.VAR,FD.CR,,, ; Variable length / implied. FDRC$A ,ERRBUF,ERRSIZ ; Locate mode / max size. FDOP$A ERRLUN,,ERRNB,FO.WRT ; Open for write access. FDBF$A ERREFN,ERRSIZ,, ; Init block buffer section. INFDB:: FDBDF$ ; FDB for the input file. OUTFDB::FDBDF$ ; FDB for the output file. ; Default file name blocks. OUTNB:: NMBLK$ MISH,OUT,,SY,0 ; Terminal output. ERRNB: NMBLK$ MISH,ERR,,SY,0 ; Error messages. DEFNB:: NMBLK$ MISH,MIS,,SY,0 ; Output file for compress. ANLNB:: NMBLK$ MISH,ANL,,SY,0 ; Output file for analyze. ; Default file name strings. DEFS: .ASCIZ ".MIS" ; These strings MUST match ANLS: .ASCIZ ".ANL" ; the above file name blocks. ; Terminal output devices: TISTR: .ASCIZ "TI0:" ; TI0: for RSX-11M. SYSIN: .ASCIZ "SYS$INPUT:" ; Input for VAX/VMS. SYSOUT: .ASCIZ "SYS$OUTPUT:" ; Output for VAX/VMS. SYSERR: .ASCIZ "SYS$ERROR:" ; Errors for VAX/VMS. .EVEN .SBTTL START - Main Line Code ;+ ; ; START - Main line code. ; ;- MISH:: ALUN$S #TILUN,#"TI,#0 ; Assign a LUN to TI0:. MOV @#.FSRPT,R0 ; Get pointer to the FSR. TST A.DFUI(R0) ; Has .FINIT been done (DDT) ? BNE 10$ ; If NE, yes (do it only once) FINIT$ ; Initialize the file storage. ; Determine what system we're running on. 10$: DIR$ #GETTSK ; Get our task parameters. CALL CHKDIR ; Check/report directive error. CLR VAXFLG ; Presume not on VAX/VMS. CMPB #5,TSKBUF+G.TSSY ; Are we running on VAX/VMS ? BNE 20$ ; If NE, no. MOV #-1,VAXFLG ; Yes, set the flag true. ; Open the input, output, and error LUNS. For RSX-11M, these ; should be asssigned at TKB time to TI:. That way they can ; be reassigned using the REAssign MCR command to a disk. ; For VAX/VMS, SYS$INPUT, SYS$OUTPUT, and SYS$ERROR are used. ; These can be reassigned using the ASSIGN/USER file SYS$xxxxx. ; Do SYS$ERROR first incase we get errors on the others. 20$: MOV #ERRFDB,R0 ; Address of error message FDB. MOV #TISTR,R1 ; Use TI0: when on RSX-11M. TST VAXFLG ; Are we runnng on VAX/VMS ? BEQ 25$ ; If EQ, no. MOV #SYSERR,R1 ; Yes, write to SYS$ERROR. 25$: CALL OPENW ; Open the LUN for write. BCS 100$ ; If CS, we had an error. ; Now do the input LUN (SYS$INPUT). MOV #TIFDB,R0 ; Address of terminal input FDB. MOV #TISTR,R1 ; Use TI0: for RSX-11M. TST VAXFLG ; Are we running on VAX/VMS ? BEQ 30$ ; If EQ, no. MOV #SYSIN,R1 ; Yes, read from SYS$INPUT. 30$: CALL OPENR ; Open the LUN for read. BCS 100$ ; If CS, we had an error. CLOSE$ ; Now close it so GCML$ can open it. ; Open the output LUN (SYS$OUTPUT). MOV #TOFDB,R0 ; Address of terminal output FDB. MOV #TISTR,R1 ; Use TI0: for RSX-11M. TST VAXFLG ; Are we running on VAX/VMS ? BEQ 40$ ; If EQ, no. MOV #SYSOUT,R1 ; Yes, write to SYS$OUTPUT. 40$: CALL OPENW ; Open the LUN for write. BCS 100$ ; If CS, we had an error. ; If running on a terminal, attach with CTRL/C AST. BITB #FD.TTY,F.RCTL(R0) ; Are we outputting to a terminal ? BEQ 50$ ; If EQ, no. ; CLOSE$ ; Yes, close the file. DIR$ #ATTACH ; Attach with CTRL/C AST. CALL CHKDIR ; Check/report directive error. 50$: MOV #GCLBLK,R0 ; Address of the control block. BISB #GE.CON,G.MODE(R0) ; Set for continuation lines. ; On VAX, change the default file name extension to .COM TST VAXFLG ; Are we running on VAX/VMS ? BEQ 60$ ; If EQ, no (default to .CMD) MOV F.DFNB(R0),R1 ; Get the file name block address. MOV #^RCOM,N.FTYP(R1) ; Change the extension to .COM 60$: BR GETCMD ; And continue ... ; We've had an error openning the input or output LUNs. 100$: CALL FILERR ; Report the error message. JMP EXISEV ; And exit with severe error. ; Get the command line and check for errors. .ENABL LSB GETCMD::MOV #GCLBLK,R0 ; Address of the control block. GCML$ R0,#PRADR,#PRLEN ; Get a command line. BCC GOTCMD ; If CC, got a command. CMPB #GE.EOF,G.ERR(R0) ; End of file detected ? BNE 10$ ; If NE, no. JMP EXIT ; Yes, exit. ; For the errors GE.IOR & GE.OPR, F.ERR in the FDB has the error code. 10$: CMPB #GE.IOR,G.ERR(R0) ; I/O error detected ? BEQ 20$ ; If EQ, yes. CMPB #GE.OPR,G.ERR(R0) ; File open error ? BEQ 20$ ; If EQ, yes. CMPB #GE.BIF,G.ERR(R0) ; Syntax error ? BEQ 30$ ; If EQ, yes. CMPB #GE.MDE,G.ERR(R0) ; Maximum @ depth exceeded ? BNE 20$ ; If NE, no (try fcs error) ERRMSG TOOMNY,<%MISH-F-TOOMANY, maximum @ file depth exceeded.> JMP EXIT ; Consider this fatal. ; Report an error message. 20$: CALL FILERR ; Report the error message. BR GETCMD ; And get the next command. ; Report a syntax error. SYNERR:: 30$: ERRMSG SYNMSG,<%MISH-E-SYNERR, syntax error in command line.> BR GETCMD ; Get the next command. .DSABL LSB ; Got a command line. GOTCMD::MOV #GCLBLK,R0 ; Address of the control block. MOV G.CMLD(R0),R3 ; Copy the string byte count. BEQ GETCMD ; If EQ, empty record. MOV G.CMLD+2(R0),R4 ; Copy the input buffer address. MOV R4,R0 ; Copy the buffer address. ADD R3,R0 ; Point to end of input string. CLRB (R0) ; Now, terminate with a null. ; Initialize various flags, counters, and storage. MOV #INFIL,INPTR ; Pointer to the input file name. MOV #OUTFIL,OUTPTR ; Pointer to the output file name. MOV #B.HEX!B.HDR!B.TOT,STATUS ; Setup the defaults for analyze. MOV #3,FIELDW ; And the field width to 3 for hex. CLR TYPOPR ; Type of operation to compress. CLR RECNUM ; Initialize the record count. CLR BLKNUM ; Initialize the block count. CLR ORGLEN ; Initialize the original length. CLR COMLEN ; Initialize the compressed length. ; ; Use TPARS to parse the command line. ; ; Inputs: ; R1 = bit 0 in the low byte controls processing of blanks/tabs: ; if 0, ignore blanks, if 1 then pass blanks and tabs. ; the high byte contains the number of characters that ; keywords are alloewed to be abbreviated (0 = exact). ; R3 = the input string byte count, ; R4 = the input buffer address. ; ; Outputs: ; R3 = zero on success or ; remaining byte count on syntax error. ; R4 = end of input string or ; updated buffer address on syntax error. ; MOV #<<400*1>+1>,R1 ; Pass blanks, match 1 character. MOV #KEYWRD,R2 ; Address of the keyword table. MOV #START,R5 ; Starting transition address. CALL .TPARS ; Now parse the command line. BCC GOGO ; If CC, parse successful. JMP SYNERR ; Else, report a syntax error. .ENABL LSB ; The command line has been successfully parsed. GOGO:: BIT #B.CMNT,STATUS ; Did we encounter a comment line ? BEQ 10$ ; If EQ, no. JMP GETCMD ; Yes, get the next command. ; Check for an input file being specified. 10$: BIT #B.IFIL,STATUS ; Was an input file specified ? BNE 15$ ; If NE, yes (continue...) ERRMSG NOIFIL,<%MISH-E-NOIFIL, you must specify an input file.> JMP GETCMD ; And gte the next command line. ; Setup the FDB for record or block I/O based on TYPOPR. 15$: CALL SETUP ; Setup the FDB appropriatly. ; Open the input file. MOV #INFDB,R0 ; Address of input file FDB. MOV #INFIL,R1 ; Address of input file name. CALL OPENR ; Try to open the input file. BCC 20$ ; If CC, success. CALL FILERR ; Else, report the error. JMP GETCMD ; And get the next command. ; If we're decompressing, process the header record. 20$: TST TYPOPR ; Are we decompressing ? BLE 25$ ; If LE, no CALL SETHDR ; Else, read the header record. BCS 40$ ; If CS, bad header record. BR 30$ ; And continue ... ; When compressing, setup the number of blocks to allocate. 25$: BMI 30$ ; If MI, we're analyzing. MOV INFDB+F.EFBK+2,R1 ; Copy the end of file block. NEG R1 ; Make it negative for non-contiguous. MOV R1,OUTFDB+F.CNTG ; Setup number of blocks to allocate. ; Now open the output file. 30$: BIT #B.OFIL,STATUS ; Do we have an output file name ? BNE 35$ ; If NE, yes TST TYPOPR ; Are we analyzing the file ? BGT 35$ ; If GT, no (put it to disk). BLT 33$ ; If LT, we're analyzing. ; When compressing, use the input file name with .MIS extension. MOV #OUTFIL,R0 ; Storage for output file name. MOV #INFIL,R1 ; Address of input file name. 31$: MOVB (R1)+,(R0) ; Copy the input file name. BEQ 35$ ; If EQ, end of input file name. CMPB (R0)+,#'. ; Have we reached the extension ? BNE 31$ ; If NE, no (copy the next byte). DEC R0 ; Backup the buffer pointer. MOV #DEFS,R1 ; Address of the default extension. CALL MOVEC ; Append the default extension. BR 35$ ; And continue ... 33$: MOV #OUTFIL,R0 ; Storage for output file name. MOV #TISTR,R1 ; Output to TI0: on RSX-11M. TST VAXFLG ; Are we running on VAX/VMS ? BEQ 34$ ; If EQ, no. MOV #SYSOUT,R1 ; Yes, write to SYS$OUTPUT. 34$: CALL MOVEC ; Copy it. ; Now open the output file. 35$: MOV #OUTFDB,R0 ; Address of output file FDB. MOV #OUTFIL,R1 ; Address of output file name. CALL OPENW ; Open the file for write. BCC DISPATCH ; If CC, we're ready to go. ; Report a file error and close the input file. CALL FILERR ; Else, report the error. 40$: CALL CLOFIL ; Close the input file. JMP GETCMD ; And get the next command. .DSABL LSB ; Dispatch to the appropriate subroutine. .WORD ANALYZ ; Anaylze routine. DISTBL: .WORD COMP ; Compress routine. .WORD DECOMP ; Decompress routine. DISPATCH:: MOV TYPOPR,R0 ; Copy the type of operation. CALL @DISTBL(R0) ; Call the appropriate routine. CALL CLOFIL ; Close the input & output files. JMP GETCMD ; And gte the next command line. .SBTTL COMP - Compress Input Blocks ;+ ; ; COMP - Compress Input Blocks. ; ; Inputs: ; The input and output files must be open. ; ; Outputs: ; All registers are preserved. ; ;- COMP:: MOV #ARGBLK,R5 ; Address of the argument block. MOV #BUFADR,O.BADR(R5) ; Setup start of output buffer. CLR @O.BLEN(R5) ; Initialize the byte count. CALL WRTHDR ; Go write the header record. BCC CLOOP ; If CC, header written successfully. RETURN ; Else, go no further. ; Get the next record from the input file. .ENABL LSB CLOOP:: BIT #B.CTRC,STATUS ; CTRL/C typed to stop compress ? BNE 100$ ; If NE, yes (stop compressing). MOV #INFDB,R0 ; Copy the input FDB address. READ$ R0 ; Read the next virtual block. BCS 90$ ; If CS, we had an error. WAIT$ R0 ; Now wait for the read. BCS 90$ ; If CS, an error occured. INC BLKNUM ; Count the number of blocks. 10$: MOV #ARGBLK,R5 ; Address of the argument block. MOV #WRKBUF,O.BADR(R5) ; Address of output work buffer (01) CLR @O.BLEN(R5) ; Address of work buffer length (01) MOV F.BKDS(R0),@O.RLEN(R5) ; Copy the block byte count. MOV F.BKDS+2(R0),O.RADR(R5) ; Copy the block buffer address. ADD @O.RLEN(R5),ORGLEN ; Accumulate original length. 20$: CALL COMPRESS ; Compress the input block. MOV #WRKBUF,R0 ; The compressed buffer address (01) MOV @O.BLEN(R5),R3 ; and the length. (01) MOV #BUFADR,R4 ; Buffer to store conversion (01) CALL DOF2T ; Do conversion to ASCII (01) MOV #BUFADR,R1 ; Address of buffer to write (01) ADD R3,COMLEN ; Accumulate the output buffer length. ; R3 is setup in DOF2T with the ; converted buffer length CALL EIGHTY ; Write eighty byte records (01) ; Check for output buffer full. ;01 TST @O.STAT(R5) ; Have we reached end of buffer ? ;01 BNE CLOOP ; If NE, no (append next record). ; The output buffer is full, now write it to the output file. 40$: ;01 CALL PADBUF ; Pad the output buffer. ;01 CALL WRTOUT ; Write the output buffer. ;01 ADD @O.BLEN(R5),COMLEN ; Accumulate the output buffer length. ;01 MOV #BUFADR,O.BADR(R5) ; Reset start of the output buffer. ;01 CLR @O.BLEN(R5) ; Initialize the buffer byte count. ;01 TST @O.RLEN(R5) ; Did we finish this input record ? ;01 BGT 20$ ; If GT, no (finish this record). BR CLOOP ; Else, get the next record. ; Error encountered reading the input file. 90$: ;01 TST @O.BLEN(R5) ; Is there anything to output ? ;01 BEQ 95$ ; If EQ, no. ;01 CALL PADBUF ; Pad the output buffer. ;01 CALL WRTOUT ; Yes, write it to the output file. 95$: CMPB F.ERR(R0),#IE.EOF ; Did we encounter end of file ? BEQ 100$ ; If EQ, yes (only error expected). CALL FILERR ; Else, report the error. 100$: CALL WRTTOT ; Output the totals. RETURN .DSABL LSB .SBTTL PADBUF - Pad Output Buffer With Continuation SCB ;+ ; ; PADBUF - Pad the output buffer with continuation SCB's. ; ; This routine fills the output buffer to its maximum length with continuation ; String Control Bytes (SCB's). This is done because HASP will blank fill ; punch record to 80 bytes which would cause problems when decompressing. ; ; Inputs: ; R5 = the compress argument block. ; ; Outputs: ; All registers are preserved. ; ;- PADBUF: CMP @O.BLEN(R5),#BUFSIZ ; Is the output buffer full ? BHIS 10$ ; If HIS, yes MOVB #B.MBON,@O.BADR(R5) ; No, fill with continuation SCB. INC O.BADR(R5) ; Adjust the buffer pointer. INC @O.BLEN(R5) ; and the buffer length. BR PADBUF ; And loop until filled. 10$: RETURN .SBTTL CLOFIL - Close Input And Output Files ;+ ; ; CLOFIL - Close the input and/or output files if open. ; ;- CLOFIL::JSR R2,$SAVVR ; Save R0 - R2 MOV #INFDB,R0 ; Address of the input FDB. TST F.BDB(R0) ; Is the input file open ? BEQ 20$ ; If EQ, no (presume no output file). CLOSE$ R0 ; Close the input file. MOV #OUTFDB,R0 ; Address of the output FDB. TST F.BDB(R0) ; Is the output file open ? BEQ 10$ ; If EQ, no TST TYPOPR ; Are we decompressing the file ? BGT 10$ ; If GT, yes (don't truncate). CALL .TRNCL ; Else truncate for compress/analyze. BR 20$ ; And use common return. 10$: CLOSE$ R0 ; Close the output file. 20$: RETURN .SBTTL Common Exit Routines ; Common exit routines: EXISUC::MOV #EX$SUC,R0 ; Set success status. BR EXST ; And exit with status. EXIWAR::MOV #EX$WAR,R0 ; Set warning status. BR EXST ; And exit with status. EXIERR::MOV #EX$ERR,R0 ; Set error status. BR EXST ; And exit with status. EXISEV::MOV #EX$SEV,R0 ; SET SEVERE STATUS ; Exit with status in R0. EXST:: EXST$S R0 ; Exit with the status. EXIT$S ; In case EXST$S fails. .SBTTL EXIT - Close Open Files And Exit ;+ ; ; EXIT - Close any open files and exit to the system. ; ;- EXIT:: CALL CLOFIL ; Close the input & output files. CLOSE$ #TIFDB ; Now close the CLOSE$ #TOFDB ; terminal input & output CLOSE$ #ERRFDB ; and error files. EXIT$S ; And exit to the system ... .END MISH