.TITLE EMB -- CONVERT FILES BETWEEN RSX AND RT-11 EMBEDDED FORMAT .IDENT /V2.04/ .DSABL GBL ; For RT-11 MACRO compatibility .ENABL LC .NLIST BEX,SYM .PSECT ; Author: Chris Doran, ; Sira Ltd., South Hill, Chislehurst, Kent, BR7 5EH, England ; ; This is a utility to convert files for use with the Sira RT-11 simulator ; package, and runs under that simulator on RSX. It will not run under RT-11, ; as it uses some "mongrel" code to access the RSX-11M file descriptor block. ; This is not a recommended way to write RSX utilities! It was done to test ; the simulator on a real job, not just test programs. ; .PSECT HELP,RO,D HLPTXT: .ASCII ;Command formats:;<15><12> .ASCII ; *outfil=infile(s) to convert FD.CR or FD.FTN to embedded;<15><12> .ASCII ; *outfil/U=infile(s) to convert embedded to RSX format;<15><12><12> .ASCII ;Note: filenames are limited to 6 chars, no directories or version numbers.;<15><12><12> .ASCII ;Switches: /E:n Expand tabs to spaces, n spaces/tab [default: 8];<15><12> .ASCII ; /C:n Compress spaces to tabs, n spaces/tab;<15><12> .ASCII ; /^ Change all LC chars to UC;<15><12> .ASCII ; /D Delete input file(s);<15><12> .ASCII ; /R:size Output fixed length records of size chars [64];<15><12> .ASCII ; /0 Don't copy null or erase characters;<15><12> .ASCII ; /8 Eight-bit characters (don't strip parity);<15><12> .ASCII ; with /U: /T Trim trailing blanks and tabs from output;<15><12> .ASCII ; /F Output with FORTRAN carriage control (default FD.CR);<15><12> .ASCII ; /L:n Limit line to n chars [132];<15><12> .ASCII ; /P:code Pad fixed records with ASCII code chars;<15><12> .ASCII ; /X Don't report lines truncated by /L:n or /R:size;<15><12> .ASCII ; /@ Precede @ OR;<15><12> .ASCII ; /# # with null if 1st non-blank after col 1;<15><12> .ASCII ; w/o /U: />:n Start each line with n spaces [8];<15><12> .ASCII ; /V:n Simulate form-feeds with n blank lines [4];<15> .BYTE 0 .EVEN ; MODIFICATIONS RECORD: ; ===================== ; V2.02 7-Oct-83 CJD ; Display line being truncated if too long. ; Reduce switch handling code. ; Add /V, /D, /0, and /X switches. ; Correct multiple input file handling. ; Set error or warning exit status. ; ; V2.03 10-Aug-84 CJD ; Correct odd address trap if /V used -- two MOVs at V: s/b MOVBs. ; Correct bug that prevented output of fixed length lines of n bytes with ; /U/R:n by complaining about (trimmed) CR. ; Don't start very first line with LF if it's blank. ; ; V2.04 19-Nov-84 CJD ; Add /@ and /# to precede these characters with a null on /U if they ; are the first non-blank character on a line, other than in column 1. ; Used for HELP file generation, to suppress special @/# processing. ; Add /8 to not strip parity, for 8-bit extended character set. .PSECT CODE,RO,I .MCALL .CSIGEN,.PRINT,.READW,.WRITW,.WAIT,.CLOSE,.GVAL,.PVAL .GLOBL ERRBYT,USERSP,USERRB,ERROR$,WARN$ .GLOBL F.RSIZ,F.RATT,F.RSIZ,F.RTYP,R.VAR,R.FIX,FD.CR,FD.FTN,.DLFNB .GLOBL FDB0 ; This is the FDB for the output file .GLOBL FDB3 ; and this for the input file .GLOBL FDB4 ; FDB4-FDB3 is the inter-FDB space LINMAX=132. ; Max length of line buffer (for unembed) HT=11 ; Horizontal tab LF=12 ; Line-feed FF=14 ; Form-feed CR=15 ; Carriage-return SPACE=40 ; Space ; Startup initialisation. INIT: .GVAL #AREA,#300 ; Get monitor configuration word BIS #200,%0 ; Setting bit 7 says there's a foreground job MOV %0,%1 ; which the simulator assumes is a despooler .PVAL #AREA,#300,%1 ; so if output is to LP:, it gets spooled BR START ; Come here to restart after serious error. ERRRST: MOV USERSP,SP ; Purge rest of stack BISB #ERROR$,USERRB ; Set error exit status ; Come here for a command line on normal start or after successful precessing. START: .CSIGEN #HSPACE,#DEFEXT,#0,#INBUFF ; Get command line (exit if ^Z) TSTB INBUFF ; Empty line? BEQ START ; Yes, ignore it MOV #LINBUF+LINMAX,LINEND ; Store buffer overflow point for variable records MOV #CLRAREA,%1 ; Address switch area to clear MOV #CLRLEN,%2 ; and size in bytes 5$: CLRB (%1)+ ; Clear bytes SOB %2,5$ ; Until done COMB ATFLAG ; ATFLAG and COMB HSHFLG ; must be set to 377 instead of 0 MOV #^C177,PARITY ; Load parity stripping mask MOV (SP)+,%1 ; Fetch no of switches BEQ 100$ ; Nothing to check if none 10$: CLR %5 ; Clear value for this switch MOV (SP)+,%2 ; Fetch switch code BPL 12$ ; Bit 15 clear means no value MOV (SP)+,%5 ; Set means we have one. Fetch it 12$: CMPB %2,#'a ; LC letter? BLO 15$ ; No, leave it alone BICB #40,%2 ; Yes, change to UC 15$: MOV #SWTLST,%3 ; Address list of switch bytes MOV #SWTSUB-2,%4 ; and action routines 20$: TST (%4)+ ; Point to next action routine TSTB @%3 ; Tried all legal switches? BEQ 30$ ; Yes, match "illegal switch" action routine CMPB %2,(%3)+ ; Compare switch with table entry BNE 20$ ; Keep looking if not found 30$: JSR PC,@(%4)+ ; Call required routine if found SOB %1,10$ ; Handle as many switches as given 100$: MOV #3,INFIL ; First input file is on channel 3 MOV #FDB3,INFDB ; Load FDB address CLR OUTBLK ; Clear output file pointers MOV #OUTBUF,OUTPTR .WAIT #3 ; Any input? BCC 50$ ; Carry set now if not TSTB HELPED ; Just asked for help? BNE START ; Yes, suppress error message .PRINT #NOIP ; Message if not BR ERRRST ; Try again 50$: .WAIT #0 ; Any output? BCC CONVRT ; Go if there is .PRINT #NOOUT ; Error if not BR ERRRST ; Try again CONVRT: CLRB INEOF ; Clear end-of-file flag MOV #INBUFF,INEND ; Reset file pointers CLR INBLK CLR COLNOW ; Clear current column CLRB SPCCNT ; Clear space feed count MOV INFDB,%0 ; Get FDB address MOVB F.RATT(%0),INRATT ; Save record attribute byte BICB #^C,INRATT ; Only use FD.CR or FORTRAN c-c bits CLR INRSIZ ; Assume records are variable CMPB #R.FIX,F.RTYP(%0) ; But if they're fixed BNE 10$ MOV F.RSIZ(%0),INRSIZ ; Get fixed size instead 10$: MOVB #377,VERY1ST ; Set very first output line flag TSTB UNEMB ; Embed or unembed? BNE UNDO ; Flag<>0 means unembed ; Convert RSX file to RT-11. FORTRAN, FD.CR, or no control is determined from ; record attributes of file. MOV #OUTCH,OUTCHR ; Output routine is OUTCH CLRB CCHAR ; Clear c-c char CLRB FORTRAN ; /F flag is ignored BITB #FD.FTN,INRATT ; File knows better! BEQ NEWLIN ; FD.CR if not FD.FTN COMB FORTRAN ; Set flag if FORTRAN NEWLIN: MOV INRSIZ,%1 ; Get fixed record size BNE 1$ ; If it is, else: JSR PC,INCH0 ; get 2 chars giving byte count TSTB INEOF ; Exit at end-of-file BNE JMPEOF MOVB %0,%1 ; Copy lo byte JSR PC,INCH0 ; Get hi byte SWAB %0 ; Put it in %0 hi BISB %0,%1 ; Then OR into %1 BEQ 6$ ;V2.03 Just do {LF+}CR if blank line 1$: TSTB INRATT ; Unless embedded c-ctrl BEQ 15$ ; (neither FD.CR nor FORTRAN), and TSTB FORTRAN ; FORTRAN control char? BEQ 6$ ; All lines start LF if FD.CR JSR PC,INCH0 ; Get c-c character TSTB INEOF ; Trap end-of-file again BNE JMPEOF DEC %1 ; Count c-c char MOVB %0,CCHAR ; Save it for end of line CMPB %0,#'1 ; Form-feed required? BNE 3$ ; No, branch MOVB #FF,%0 ; Yes, make it the first char BR 10$ ; Go output FF 3$: CMPB %0,#'0 ; No, double-spacing? BNE 4$ ; No, try '+' MOVB #LF,%0 ; '0' needs a blank line JSR PC,OUTCH ; which is an LF (non-compressible) MOVB #CR,%0 ; + CR JSR PC,OUTCHC ; BR 6$ ; + another LF (BR not reqd as next test fails) 4$: CMPB %0,#'+ ; Append? BEQ 15$ ; Yes, no prefix required 6$: TSTB VERY1ST ; All others start with LF BNE 15$ ; Unless this is the very first line of output 7$: MOVB #LF,%0 ; Most c-c's start line with LF 10$: JSR PC,OUTCHV ; Output first char 15$: TST %1 ; Blank line? BEQ 30$ ; Just end CR if so MOVB RIGSHI,SPCCNT ; Else queue right shift spaces ADD RIGSHI,%1 ; Adding them to chars in line CLR COLNOW ; Clear current column CLR COLNXT 20$: JSR PC,INCH ; Get another character TSTB INEOF ; Checking for e-o-f as usual BNE 30$ ; End line if so JSR PC,OUTCHV ; Output char if not SOB %1,20$ ; Loop %1 times 30$: TSTB INRATT ; Unless embedded c-ctrl BEQ 40$ ; and CMPB CCHAR,#'$ ; unless FORTRAN '$' c-c BEQ 40$ MOVB #CR,%0 ; End line with CR JSR PC,OUTCHC 40$: CLRB VERY1ST ; Not very first line now TSTB INEOF ; Check end-of-file again BNE JMPEOF ; Branch if end TST INRSIZ ; If there was a byte count BNE NEWLIN ; (wasn't if fixed length records) INC INPTR ; Make sure we are on a word boundary BIC #1,INPTR ; By adding 1, and removing it if byte odd BR NEWLIN ; Go again JMPEOF: JMP EOF ; Finish up output file ; Un-embed. Build up lines in LINBUF, to get count, then output RSX-like ; variable-length record -- one word byte count, FORTRAN c-c char if reqd, ; record, and null byte if odd length. ; Note that the simulator has opened the output file with embedded c-c, and ; fixed length records. Change the FDB to reflect our actual output. UNDO: MOV #PUTBACK,OUTCHR ; Compression character handler MOVB #CR,LASTCH ; Pretend first line started with CR MOVB #FD.CR,FDB0+F.RATT ; Assume we need FD.CR control TSTB FORTRAN ; But if it's FORTRAN BEQ 10$ MOVB #FD.FTN,FDB0+F.RATT ; make it FD.FTN instead MOVB #SPACE,NXTCCH ; Clear overprint c-c flag 10$: TSTB FIXED ; Fixed length records? BNE UNDLIN ; Keep length if so MOVB #R.VAR,FDB0+F.RTYP ; Else set variable-length CLR FDB0+F.RSIZ ; Will store max record length here ; Start of new lineoutput . UNDLIN: MOV #LINBUF-1,%1 ; Address line buffer MOVB #200,@%1 ; Set prefix byte to untrimmed char BICB (%1)+,NOWARN ; Use it as mask to clear in-line warning bit MOV %1,%3 ; Copy pointer for later MOVB NXTCCH,CCHAR ; Set FORTRAN c-c char (space or saved '+') CMPB LASTCH,#FF ; If last line terminated on FF BNE 5$ MOVB #'1,CCHAR ; FORTRAN c-c char is '1' TSTB FORTRAN BNE 5$ ; But if FD.CR control required, MOVB #FF,(%1)+ ; Make it the first character of this line 5$: MOVB #SPACE,NXTCCH ; Reset next line c-c char MOVB ATFLAG,ATLINE ; Copy /@ flag (0 if not set) MOVB HSHFLG,HSHLIN ; /# flag ditto 10$: JSR PC,INCH ; Fetch a character TSTB INEOF ; End of file? BNE UNDEOF ; Yes, treat as end-of line CMPB %0,#LF ; Line-feed? BEQ 12$ ; Yes, LF marks end-of-line CMPB %0,#FF ; So does form-feed BNE 13$ 12$: TSTB FORTRAN ; Unconditionally if FORTRAN c-c BNE UNDEOL CMPB LASTCH,#CR ; Must be preceded by CR if FD.CR BEQ UNDEOL BR 15$ ; Otherwise, leave them embedded 13$: CMPB LASTCH,#CR ; Carriage-return w/o LF? BNE 15$ TSTB FORTRAN ; Ends record if output file has FORTRAN c-c BEQ 15$ ; Embed it if not MOVB #'+,NXTCCH ; Next line requires '+' c-c DEC INPTR ; Put back this char for start of next line BR UNDEOL ; Do end of line now 15$: MOVB %0,LASTCH ; Remember the last char processed 16$: CMP %1,LINEND ; Not end, room to store char? BLO 20$ ; Yes, do so CMPB %0,#CR ;V2.03 No, trying to store a CR? BEQ 20$ ;V2.03 That's OK, they're trimmed off TSTB NOWARN ; Warning suppressed (or done on this line)? BNE 10$ ; Yes, just skip char .PRINT #TOLONG ; No, else warning message CLRB @%1 ; Make string ASCIZ .PRINT %3 ; Show line so far BISB #WARN$,USERRB ; Set warning exit status BISB #200,NOWARN ; Don't repeat message on this line BR 10$ ; Get chars to skip them ; If this is the first non-blank character on the line, and not column 1, ; prefix an @ or # with a null if /@ or /# is on (ATFLAG or HSHFLG) <> 0. ; Note that this code assumes that ATLINE(FLAG) and HSHLIN(FLG) are set to '@' ; and '#' if suppression is required, 377 if not. 20$: CMP %1,#LINBUF ; 1st char? BLOS 50$ ; Yes, skip test CMPB %0,ATLINE ; Prefix to @ required? BEQ 40$ ; Yes, go do it 30$: CMPB %0,HSHLIN ; Not @, test for # BNE 50$ ; No, go store 40$: CLRB (%1)+ ; First @ or #, prefix with null COMB ATLINE ; Clear flags for this line COMB HSHLIN ; by setting bit 7 BR 16$ ; Back to re-store @/# (if room) ; No prefix required: 50$: MOVB %0,(%1)+ ; Store char CMPB %0,#SPACE ; Space? BEQ 10$ ; Yes, go get another char CMPB %0,#HT ; Tab? BEQ 10$ ; Yes, ditto MOVB #377,ATLINE ; No, clear @ flag and MOVB #377,HSHLIN ; # flag for this line -- no prefix needed BR 10$ ; Go get another char UNDEOF: CMP %1,#LINBUF ; End of I/P. See if any odd chars in line buffer BLOS EOF ; Just end O/P file if not, else fake end of line TSTB -(%1) ; Trim off odd nulls BEQ UNDEOF INC %1 UNDEOL: CMPB -(%1),#CR ; Trim off a trailing CR BEQ 10$ MOVB #'$,CCHAR ; FORTRAN prompt c-ctrl if we didn't have one BR 15$ 10$: CMPB -(%1),#CR ; Trim off multiple CR's BEQ 10$ ; 15$: TSTB TRIM ; and if trim flag is set BEQ 20$ CMPB @%1,#SPACE ; also remove spaces, BEQ 10$ CMPB @%1,#HT ; tabs, BEQ 10$ TSTB @%1 ; and nulls BEQ 10$ 20$: MOVB %0,LASTCH ; Save line terminator CMP %1,LINEND ; Unless already there (line overflowed) ADC %1 ; Point just beyond last char TSTB EXPCPR ; Compress line? BGE 25$ ; No, just output CLR COLNOW ; Clear column pointers CLR COLNXT ; Read LINBUF character by character, compressing back into itself. MOV %3,%2 ; Pointer to chars to fetch (LINBUF) MOV %2,%4 ; Put-back pointer 22$: CMP %2,%1 ; Reached end of line? BHIS 24$ ; Yes, done compression MOVB (%2)+,%0 ; No, get next character JSR PC,OUTCPR ; Process it BR 22$ ; Repeat 24$: MOV %4,%1 ; Point to end of compressed line 25$: CMP %1,%3 ; Empty record? BEQ 40$ ; Branch if so TSTB FORTRAN ; FORTRAN carriage-control required? BEQ 40$ MOVB CCHAR,-(%3) ; Yes, put in control char 40$: SUB %3,%1 ; Compute line length MOV %1,%4 ; Make a copy TSTB FIXED ; Fixed length records? BNE 50$ ; No, byte count required MOV %1,%0 ; Copy line length JSR PC,OUTCH ; Output lo byte SWAB %0 ; Get hi byte JSR PC,OUTCH ; Output that too 50$: TST %1 ; Any chars (left) in buffer? BLE 60$ ; No, done MOVB (%3)+,%0 ; Yes, fetch char JSR PC,OUTCH DEC %1 ; Dec counter BR 50$ ; Repeat until done 60$: TSTB FIXED ; Fixed length records? BEQ 80$ ; No, branch 70$: CMP %4,FDB0+F.RSIZ ; Yes, reached end of record? BHIS 90$ ; Done if so MOVB PBYTE,%0 ; No, load pad character JSR PC,OUTCH ; Append to buffer INC %4 ; Increment count BR 70$ ; and repeat 80$: BIT #1,%4 ; Make sure variable record BEQ 90$ ; Ends on a word boundary CLR %0 ; If not, pad with a null JSR PC,OUTCH CMP %4,FDB0+F.RSIZ ; Is this the longest record so far? BLOS 90$ ; No, branch MOV %4,FDB0+F.RSIZ ; Yes, note longest record 90$: TSTB INEOF ; End of input file? BNE EOF ; Yes, done JMP UNDLIN ; No, start a new line ; At end of input, force O/P of last block. EOF: TSTB DELINP ; Delete input file after processing? BEQ 10$ ; No, branch MOV INFDB,%0 ; Yes, load FDB address JSR PC,.DLFNB ; Must use RSX routine -- don't know filename 10$: MOV #INFIL,%1 ; Address current input file channel no .CLOSE @%1 ; Close it (even if .DLFNB already did) INC @%1 ; Move to next one CMP @%1,#9. ; Reached last? BHIS 20$ ; Yes, go get another command line ADD #FDB4-FDB3,INFDB ; No, update FDB pointer too .WAIT @%1 ; Is this I/P file open? BCS 20$ ; No, done JMP CONVRT ; Yes, append to last 20$: MOV OUTPTR,%1 ; No, get output buffer pointer CLRB @%1 ; Put in a null in case odd no of bytes SUB #OUTBUF,%1 ; Compute no of bytes BEQ 30$ ; In last block. Branch if none ASR %1 ; Change bytes to words ADC %1 ; 1 more if odd .WRITW #AREA,#0,#OUTBUF,%1,OUTBLK ; Write last block 30$: .CLOSE #0 ; No, close O/P file JMP START ; and start again ; Single character output routine -- print char in %0 OUTCH: CMP OUTPTR,#OUTBUF+512. ; All chars filled? BLO OUTCHA ; No put in another MOVB %0,-(SP) ; Save char .WRITW #AREA,#0,#OUTBUF,#256.,OUTBLK MOVB (SP)+,%0 ; Restore char BCS WTERR ; Carry set on error INC OUTBLK ; Next block next time MOV #OUTBUF,OUTPTR ; Reset pointer ; Copy char to output. OUTCHA: MOVB %0,@OUTPTR ; Copy it INC OUTPTR ; Inc pointer RTS PC ; And return WTERR: .PRINT #OUTERR ; Print message JMP ERRRST ; Restart ; Single character input routine -- input char to %0, returning multiple-spaces ; for tabs if expanding. INCH: TSTB SPCCNT ; Any spaces required? BLE 10$ ; No, get a new char 5$: MOVB #SPACE,%0 ; Yes, return a space DECB SPCCNT ; Note we have BR 101$ ; Tally current position if required 10$: JSR PC,INCH0 ; Get a character 101$: TSTB EXPCPR ; Tab expansion required? BLE 50$ ; No, just return CMPB %0,#40 ; Printing char? BHIS 45$ ; Yes, just note position on line CMPB %0,#CR ; Carriage-return? BNE 12$ 11$: CLR COLNOW ; Yes, reset to margin now RTS PC ; and return with CR 12$: CMPB %0,#HT ; Horiz tab? BNE 40$ ; No, branch MOV COLNOW,%5 ; Yes, get current position on line JSR PC,TAB ; Find next tab stop MOV %5,-(SP) ; Copy required position SUB COLNOW,@SP ; Compute no of spaces to return TSTB UNEMB ; If reading an RSX file, BNE 20$ ; but not if converting to one ADD @SP,%1 ; Note that this increases bytes in record DEC %1 ; by no of extra chars (=spaces-tab already counted) 20$: MOVB (SP)+,SPCCNT ; Save space count BR 5$ ; Go return space 40$: CMPB %0,#10 ; Backspace? BNE 50$ ; Return all else, w/o changing line position DEC COLNOW ; Dec line position if so BMI 11$ ; Don't allow backspace past LH margin 45$: INC COLNOW ; Yes, note position on line 50$: RTS PC INCH0: CMP INPTR,INEND ; Buffer emptied? BLO 10$ ; No, get byte .READW #AREA,INFIL,#INBUFF,#256.,INBLK BCS RDERR ; Error if carry INC INBLK ; New block next time MOV #INBUFF,INPTR ; Character zero ASL %0 ; Double words read giving bytes MOV #INBUFF,INEND ; Set end pointer ADD %0,INEND ; Allowing for no of chars actually read 10$: MOVB @INPTR,%0 ; Get char INC INPTR ; Advance pointer for next BIC PARITY,%0 ; Strip parity bit unless /8 CMPB %0,#'a ; And if lower-case letter BLO 20$ CMPB %0,#'z BHI 20$ BICB LCASE,%0 ; change to upper if required (mask=0 if not) 20$: TSTB IGNULL ; Skip nulls and deletes? BEQ 30$ ; No, keep them TSTB %0 ; Yes, do we have a null? BEQ INCH0 ; Do it all again if so CMPB %0,#177 ; Or delete? BEQ INCH0 ; Skip them too 30$: RTS PC ; And return ; Read error RDERR: TSTB @#ERRBYT ; Test emt error byte BEQ INCHE ; 0=EOF can handle that .PRINT #INERR ; But nothing else JMP ERRRST ; Exit abnormal ; End of file INCHE: INCB INEOF ; Input EOF:=TRUE RTS PC ; Return with flag ; Output character, with space compression if required, replacing FF by LFEED ; line-feeds if LFEED<>0. Called from RSX->RT code only. OUTCHV: CMPB %0,#FF ; Form-feed? BNE OUTCHC ; No, output normally MOVB LFEED,-(SP) ; Yes, get no of lines to replace it with BEQ 20$ ; 0 means output unchanged 10$: MOVB #LF,%0 ; <>0 means output LFs DECB @SP ; Repeating until done BEQ 20$ ; (Last is output via OUTCHC) JSR PC,OUTCH ; Output any other LF TST COLNOW ; and unless embedded in text BNE 10$ MOVB #CR,%0 ; Follow each except last with CR so that JSR PC,OUTCH ; a convert back will produce blank lines BR 10$ 20$: TST (SP)+ ; Done (or no replacement). Purge stack ; BR OUTCHC ; Fall through for FF or last LF ; Space compression routine. Call with character in %0, and OUTCHR containing ; address of routine to output it (if required). For RSX->RT file conversion, ; OUTCHR will contain INCH, the file output routine. For RT->RSX conversion, ; the character is just put back to the string being compressed, and OUTCHR ; contains PUTBACK. ; ; Save up spaces, tabs, and backspaces until it's really necessary to print ; them. When it is, use tabs if at all possible. ; COLNXT always contains the column at which the next non-whitespace character ; should be placed. ; COLNOW contains the column we are actually at, not including up-coming ; spaces/tabs/backspaces. ; Note that non-printing characters don't update either. OUTCHC: TSTB EXPCPR ; Compression required? BGE OUTC ; Not if flag >=0 OUTCPR: TSTB %0 ; Null? BEQ 5$ ; Yes, don't output at all CMPB %0,#177 ; Delete? BEQ 5$ ; ditto CMPB %0,#SPACE ; Space? BHI 100$ ; ASCII codes > space are all printing BNE 10$ ; Not space, branch INC COLNXT ; Just remember a space 5$: RTS PC ; and return 10$: CMPB %0,#HT ; Horiz tab? BNE 20$ ; No, branch MOV COLNXT,%5 ; Yes, load required position JSR PC,TAB ; compute position of next tab stop MOV %5,COLNXT ; to get new required column RTS PC ; That's all for now 20$: CMPB %0,#CR ; Carriage-return? BNE 30$ ; No, branch CLR COLNOW ; Yes, move to column 0 CLR COLNXT BR OUTC ; Go output 30$: CMPB %0,#10 ; Backspace? BNE 100$ ; Store anything else now DEC COLNXT ; Yes, step back 1 char BGE 40$ ; Don't go past left margin CLR COLNXT ; Stop there 40$: RTS PC ; Return ; Have a non-whitespace character. Flush any intermediate spaces before ; storing it. 100$: MOV %0,-(SP) ; No, save the character to be output 105$: CMP COLNOW,COLNXT ; Are we at the right place anyway? BEQ 140$ ; Yes, no spacing required BGT 135$ ; Backspace if COLNOW>COLNXT ; Output a tab if there is a tab stop between COLNOW and COLNXT. If not, ; just print the odd spaces (if any). MOV COLNXT,-(SP) ; See if only 1 space is required SUB COLNOW,@SP DEC (SP)+ BLE 120$ ; If so, a space is as good as a tab 110$: MOV COLNXT,%5 ; Copy required column JSR PC,TAB ; Find required tab column SUB TABSIZE,%5 ; which is next column-tab size CMP COLNOW,%5 ; Passed this tab stop already? BGE 120$ ; Yes, can't use any more tabs MOVB #HT,%0 ; No, put in a tab JSR PC,@OUTCHR ; Output tab MOV COLNOW,%5 ; Get old position JSR PC,TAB ; Find next tab stop MOV %5,COLNOW ; Which is position now BR 110$ ; and repeat ; Output odd spaces 120$: MOVB #SPACE,%0 ; Load space character 130$: CMP COLNOW,COLNXT ; Reached required position already? BGE 140$ ; Yes, done JSR PC,160$ ; No, output space, incrementing COLNOW BR 130$ ; and repeat until done ; Backspaces required 135$: MOVB #10,%0 ; Load backspace JSR PC,@OUTCHR ; Output it DEC COLNOW ; Point back one character BR 105$ ; Go see if done ; All spaces written. Restore the character to be printed and print it. 140$: MOV (SP)+,%0 ; Load character CMPB %0,#SPACE ; Control code not already handled? BLOS OUTC ; Yes, these don't move carriage INC COLNXT ; No, note where next column is 160$: INC COLNOW ; and where we are OUTC: JMP @OUTCHR ; Output character ; Character "output" routine for RT11->RSX conversion. Just put character ; where %4 points. PUTBACK:MOVB %0,(%4)+ ; Store char RTS PC ; and return ; Compute column for next tab stop, if current column is in %5. New column ; return to %5. TAB: MOV %4,-(SP) ; Save %4 CLR %4 ; finding position of last tab DIV TABSIZE,%4 ; =current position/chars per tab INC %4 ; add 1 for next tab MUL TABSIZE,%4 ; Change back to chars MOV (SP)+,%4 ; Restore %4 RTS PC ; Switch table. List of chars and action routines if matched: SWTLST: .ASCIZ "?UFRPECTL^>VDX08@#" .EVEN SWTSUB: .WORD QM,U,F,R,P,E,C,T,L,UP,SHR,V,D,X,ZERO,EIGHT,AT,HASH,ILLSWT QM: .PRINT #HLPTXT ; ? = print help text MOVB %2,HELPED ; Note help requested RTS PC U: MOVB %2,UNEMB ; Set un-embed flag if UC or LC 'U' RTS PC F: MOVB %2,FORTRAN ; Set FORTRAN output flag RTS PC R: MOVB %2,FIXED ; Note fixed length records TST %5 ; Value given? BNE 10$ ; Yes, use it MOV #64.,%5 ; No, default to 64. 10$: MOV %5,FDB0+F.RSIZ ; Set record size ; BR L ; Use L processor to check/set LINEND pointer L: TST %5 ; Switch value? BEQ 10$ ; No, keep default CMP %5,#LINMAX ; Line too long? BHI ILLVAL ; Yes, error MOV %5,LINEND ; OK, set line overflow pointer ADD #LINBUF,LINEND 10$: RTS PC P: MOVB %5,PBYTE ; Load pad byte value (default null) RTS PC E: MOVB %2,EXPCPR ; Set flag +ve to expand tabs to spaces BR SETTAB ; Set TABSIZE C: MOVB #-1,EXPCPR ; Set flag -ve to compress spaces to tabs SETTAB: MOV %5,TABSIZE ; Load given tab size BNE 10$ ; if there is a switch value MOV #8.,TABSIZE ; Use 8 if not 10$: RTS PC T: MOVB %2,TRIM ; Set trim flag RTS PC UP: MOVB #40,LCASE ; ^ = change LC->UC -- load mask RTS PC SHR: MOV %5,RIGSHI ; Load switch value BNE 10$ ; If any MOV #8.,RIGSHI ; Use 8. if not 10$: RTS PC V: MOVB %5,LFEED ;V2.03 Load no of lines for simulated FF BNE 10$ ; If given MOVB #4,LFEED ;V2.03 Default 4 lines if not 10$: RTS PC D: MOVB %2,DELINP ; Set delete input flag RTS PC X: MOVB %2,NOWARN ; Don't report line truncation RTS PC EIGHT: CLRB PARITY ; Keep 8 bits, don't strip parity RTS PC ZERO: MOVB %2,IGNULL ; Ignore nulls and deletes RTS PC AT: MOVB %2,ATFLAG ; Prefix 1st @ with null RTS PC HASH: MOVB %2,HSHFLG ; Prefix 1st # with null RTS PC ILLSWT: .PRINT #NOSWIT ; Error -- no such switch BR ABOCMD ; Get another command ILLVAL: .PRINT #TOOBIG ; Error -- switch value too big ABOCMD: JMP ERRRST ; Start again .PSECT DATA,RW,D OUTBLK: 0 ; Output file block no OUTPTR: OUTBUF ; Points to next char space OUTBUF: .BLKB 512. ; Output buffer INFIL: 3 ; Current input file, start with 3 INFDB: .WORD FDB3 ; RSX file descriptor block address INBLK: 0 ; Input file block no INPTR: INBUFF+512. ; Input buffer pointer INEND: INBUFF ; End of data pointer INBUFF: .BLKB 512. ; Input buffer AREA: .BLKW 10 ; EMT request block area DEFEXT: .RAD50 /TXTTXTTXTTXT/ ; All files default extension .TXT LINEND: .WORD LINBUF+LINMAX ; Line buffer overflow pointer TABSIZE:.WORD 8. ; Tab stop multiplier OUTCHR: .WORD OUTCH ; Character output routine address PARITY: .WORD ^C177 ; Parity stripping mask CLRAREA: ; This region is set to 0 before each command fetch COLNOW: .WORD 0 ; Current position on line, for tab expansion COLNXT: .WORD 0 ; Required position for compression RIGSHI: .WORD 0 ; No of spaces at start of each line INRSIZ: .WORD 0 ; F.RSIZ of input file if fixed, 0 if variable INRATT: .BYTE 0 ; F.RATT byte of input file LCASE: .BYTE 0 ; Case change mask, if required SPCCNT: .BYTE 0 ; No of spaces pending for tab expansion LFEED: .BYTE 0 ; No of blank lines for FF. 0 = output unchanged TRIM: .BYTE 0 ; Trim trailing spaces/tabs/nulls (unembed only) EXPCPR: .BYTE 0 ; -ve = compress spaces to tabs, +ve = expand tabs to spaces INEOF: .BYTE 0 ; I/P EOF flag HELPED: ; Note if help given on command line VERY1ST:.BYTE 0 ; Very first line flag CCHAR: .BYTE 0 ; FORTRAN c-c char for this line LASTCH: .BYTE 0 ; Last character output UNEMB: .BYTE 0 ; Embed/un-embed flag FORTRAN:.BYTE 0 ; FORTRAN c-c output flag FIXED: .BYTE 0 ; Fixed length records required? PBYTE: .BYTE 0 ; Fixed length record pad byte DELINP: .BYTE 0 ; Delete input files NOWARN: .BYTE 0 ; Suppress line truncation warnings IGNULL: .BYTE 0 ; Ignore nulls and deletes ATFLAG: .BYTE 0 ; Prefix 1st @ with null HSHFLG: .BYTE 0 ; Prefix 1st # with null CLRLEN=.-CLRAREA ; End of pre-cleared area ATLINE: .BYTE 0 ; @ flag for current line HSHLIN: .BYTE 0 ; # flag for current line NXTCCH: .BYTE 40 ; Save c-c char for next .BYTE 0 ; Guard leader byte, for trim and FORTRAN c-c LINBUF: .BLKB LINMAX ; Line buffer for unembed operations .BYTE 15 ; Guard end byte, always CR NOIP: .ASCIZ "?EMB-F-No input" NOOUT: .ASCIZ "?EMB-F-No output" TOOBIG: .ASCIZ "?EMB-F-Switch argument too big" NOSWIT: .ASCIZ "?EMB-F-No such switch" OUTERR: .ASCIZ "?EMB-F-Output error" INERR: .ASCIZ "?EMB-F-Input error" TOLONG: .ASCIZ "?EMB-W-Line truncated to:" .EVEN HSPACE=. ; (Dummy) handler space .END INIT