.TITLE GREP - Get Regular Expression .IDENT /V02.01/ ; External release .ENABL LC ; Enable lowercase .NLIST BEX ; Don't list binary extensions .NLIST CND ; Don't list unsatisfied conditionals .NLIST SYM ; Don't list the symbol table .SBTTL **************************** NOTE WELL! **************************** .SBTTL .SBTTL This software is provided by Machine Intelligence and Industrial .SBTTL Magic (hereafter referred to as "MIIM") under a non-exclusive single .SBTTL site license agreement. The ownership of this software is not .SBTTL transferred to the licensee and remains with MIIM. Copyright (c) .SBTTL 1990, Bruce R. Mitchell. All rights, including reproduction by any .SBTTL means whatsoever, remain with MIIM. .SBTTL .SBTTL MIIM makes no warranties, either express or implied, with respect to .SBTTL this software, its quality, performance, merchantability, or fitness .SBTTL for any particular purpose. MIIM software is licensed "AS IS". The .SBTTL entire risk as to its quality and performance is with the licensee. .SBTTL Should this software prove defective following its licensing, the .SBTTL licensee assumes the entire cost of all necessary servicing, repair .SBTTL or corrections and any incidental or consequential damages. .SBTTL .SBTTL In no event shall MIIM be liable for any damages resulting from the .SBTTL use of this software, including direct, indirect, incidental or .SBTTL consequential damages, regardless of the legal theory asserted .SBTTL including negligence and/or strict liability, even if MIIM has been .SBTTL advised of the possibility of such damages. .SBTTL .SBTTL The foregoing limitations of remedies and liabilities may not be .SBTTL altered. .SBTTL .SBTTL **************************** NOTE WELL! **************************** .SBTTL .SBTTL ; GGGGGGGG RRRRRRRRR EEEEEEEEEE PPPPPPPPP ; GGGGGGGG RRRRRRRRR EEEEEEEEEE PPPPPPPPP ; GG RR RR EE PP PP ; GG RR RR EE PP PP ; GG RRRRRRRRR EEEEEEEE PPPPPPPPP ; GG RRRRRRRRR EEEEEEEE PPPPPPPPP ; GG GGGG RR RR EE PP ; GG GGGG RR RR EE PP ; GG GG RR RR EE PP ; GG GG RR RR EE PP ; GGGGGGGG RR RR EEEEEEEEEE PP ; GGGGGGGG RR RR EEEEEEEEEE PP .SBTTL Introduction ; ; GREP - Get Regular Expression ; ; Original Author: ; Bruce C. Wright ; Author: ; Bruce R. Mitchell ; Source Site: ; Machine Intelligence and Industrial Magic ; 390 North Shore Drive ; RR 1, Box 216 ; Fountain City, WI 54629 ; Source Hardware and Operating System: ; DEC Professional 380 under P/OS V3.0 ; Target Site: ; Unknown ; Target Hardware and Operating System: ; Unknown ; Revision History: ; ; xx-May-79 Ray French vxx.xx ; xx-Mar-80, Jim Downward vxx.xx ; xx-Mar-81, Jim Downward vxx.xx ; xx-xxx-xx, Glenn Everhart vxx.xx ; 17-Mar-90, Bruce R. Mitchell V2.00 ; Revision "The Traveller" ("watch the stars") ; Complete top to bottom rewrite for wildcard version handling, ; self-identification, pointer lines, and big multi-buffering ; 23-Apr-90, Bruce R. Mitchell V2.01 ; Minor rev to fix non-wildcard file handling in .FIND loop .PAGE .SBTTL Command Syntax ; GREP [outfile =] /SE:"string" [/PO] [/EX] [/ID] [/LI] ; ; outfile May be any legal filename for the output listing. If ; not specified, output will go to the user's terminal. ; If other than a terminal (file or LP:) it output will ; be preceded by the invoking command line. Multiple ; searches to the same output file will be appended and ; preceded by a formfeed and line of asterisks. ; ; infile May be any filespec, and may incorporated wildcard file ; names. Wildcard directories are not supported. ; ; string May be any printing ASCII string with no restrictions. ; A query character '?' in the search string matches one ; character in the input regardless of what it is. ; ; The /PO(inter) switch prints a line underneath the found record ; with a pointer underneath the search string. ; ; The /EX(act) switch matches only records which exactly match the ; search string. ; ; The /ID(ent) switch prints information on the built parameters ; of the GREP task. ; ; The /CO(ntinuation):n switch (unimplemented so far) lists the match ; line and n lines after it in the source. .PAGE .SBTTL Macro Calls and Definitions .MCALL ALUN$ ; Assign LUN to device .MCALL CLOSE$ ; Close file .MCALL DIR$ ; Execute directive .MCALL EXST$S ; Exit with status .MCALL FDAT$A ; Define FDB record attribute info .MCALL FDBDF$ ; Allocate space for FDB .MCALL FDRC$A ; Define FDB record access info .MCALL FEAT$ ; Test for system feature .MCALL GCMLD$ ; Define GCML$ offsets .MCALL GLUN$ ; Get LUN information .MCALL FDBF$A ; Define FDB buffer info .MCALL GET$ ; Get record from file .MCALL NMBLK$ ; Allocate space for filename block .MCALL OFID$R ; Open by file-ID .MCALL OFNB$A ; Open by FNB for append .MCALL OFNB$W ; Open by FNB for write .MCALL PUT$ ; Put a record to a file .MCALL QIOW$ ; Queue I/O and wait .MCALL GCMLB$ .MCALL GCML$ .MCALL CSI$ .MCALL CSI$1 .MCALL CSI$2 .MCALL CSI$SW .MCALL CSI$SV .MCALL CSI$ND .MCALL FINIT$ .MCALL FSRSZ$ .MCALL FDOP$A CSI$ GCMLD$ .MACRO PRINT STRING MOV #STRING, TTYOUT+Q.IOPL MOV #STRING'L, TTYOUT+Q.IOPL+2 DIR$ #TTYOUT .ENDM .PAGE .SBTTL Local Definitions ; LUNs and event flag numbers TILUN = 1 ; Terminal I/O LUN CMLUN = 2 ; Command file I/O LUN IFLUN = 3 ; Input file I/O LUN OFLUN = 4 ; Output file I/O LUN AQLUN = 5 ; ACP info QIO LUN TIEFN = TILUN ; First terminal I/O EFN CMEFN = CMLUN ; Command file I/O EFN IFEFN = IFLUN ; Input file I/O EFN OFEFN = OFLUN ; Output file I/O EFN AQEFN = AQLUN ; ACP info QIO I/O EFN ; CSI control bits SW.SEA = 1 ; /SE = Search string SW.CON = 2 ; /CO = Continue listing next n lines SW.EXA = 4 ; /EX = Search string exact as given SW.LIN = 10 ; /LI = Show line counter when found SW.POI = 20 ; /PO = Show string pointer when found SW.IDN = 40 ; /ID = Tell user about task status ; ASCII codes HT = 11 ; Horizontal tab FF = 14 ; Form feed ESC = 33 ; Escape BK = 40 ; Blank ; Miscellaneous definitions CBFLEN = 256. ; Scratch buffer length IBFLEN = 256. ; Input file move mode buffer length SBFLEN = 82. ; Search string buffer length BBCT = 16. ; Set big-buffering block count to 16 R$$FEA = 1 ; Assume FEAT$ directive available .PAGE .SBTTL .SBTTL Data .SBTTL .SBTTL External PSECTs ; ; TKB extends PSECT $$DBTS, filling it with information including ; the date and time of the Taskbuild ; .PSECT $$DBTS, RW, D, LCL $DBTS:: ; Storage area for TKB time/date ; ; Allocate file storage region space ; FSRSZ$ <<2*BBCT>+1> ; Allocate file buffer space .PAGE .SBTTL Internal PSECTs ; ; PSECT for data segments generated by this source file ; .PSECT GREDAT, RW, D .PAGE .SBTTL File Descriptor Blocks ; Input file FDB IFLFDB: FDBDF$ ; START OF FDB FDBF$A IFEFN,, 2, FD.RAH FDOP$A IFLUN, CSIBLK+C.DSDS,, FO.RD!FA.SHR, FA.ENB!FA.DLK!16. FDRC$A FD.PLC, IFLBUF, IBFLEN FNDFNB: NMBLK$ ; FDB for output file OFLFDB: FDBDF$ FDAT$A R.VAR, FD.CR, 132. FDBF$A OFEFN FDOP$A OFLUN .PAGE .SBTTL Control Blocks ; COMMAND LINE MACROS AND DATA BLOCKS GCLBLK: GCMLB$ 1, GRE,, CMLUN .EVEN CSIBLK: .BLKB C.SIZE ; CSI BLOCK .EVEN SWTABL: CSI$SW SEARCH, SW.SEA, SWORD,,, SVTABL CSI$SW CONT, SW.CON, SWORD,,, SVTB2 CSI$SW EXACT, SW.EXA, SWORD CSI$SW IDENT, SW.IDN, SWORD CSI$SW LINE, SW.LIN, SWORD CSI$SW POINTER, SW.POI, SWORD CSI$ND SVTABL: CSI$SV ASCII, STRBUF, SBFLEN CSI$ND SVTB2: CSI$SV DECIMAL,COSIZ,2 ;2 BYTE DECIMAL NO CSI$ND .PAGE .SBTTL Directive Parameter Blocks ; Assign LUN DPBs ALUNAQ: ALUN$ AQLUN, 0, 0 ALUNTI: ALUN$ TILUN, TI, 0 ALUNCM: ALUN$ CMLUN, TI, 0 .IF DF R$$FEA ; If FEAT$ directive available ; Test for System Feature DPBs VERTST: FEAT$ FE$DVN .ENDC ; DF R$$FEA ; Get LUN Information DPBs GLINFO: GLUN$ 0, GLIBUF ; Queue I/O DPBs GETTTY: QIOW$ SF.GMC, TILUN, TIEFN,, IOSTAT,, GETNAM: QIOW$ IO.RAT, AQLUN, AQEFN,, IOSTAT,, <0, ATTLST, 0, 0, 0, 0> TTYOUT: QIOW$ IO.WVB, TILUN, TIEFN,, ,, <0, 0, 40> .PAGE .SBTTL Tables ; Table of file extensions which should never be searched IEXTBL: .RAD50 \TSK\ ; Task images .RAD50 \OBJ\ ; Object files .RAD50 \STB\ ; Symbol tables .RAD50 \OLB\ ; Object libraries .RAD50 \SYS\ ; System images .RAD50 \CDA\ ; Crash dumps .WORD 0 ; End of table ; Get terminal attributes control list TATLST: .BYTE TC.DEC, 0 ; Get DEC_CRT TATLEN = . - TATLST ; Get file attributes control list ATTLST: .BYTE -5, 10. ; Get filename, 10 bytes .WORD FNMBLK ; Into buffer FNMBLK .WORD 0 ; End of list .PAGE .SBTTL Strings and Messages MS00: .ASCII \ \ MS00L = . - MS00 MS01: .ASCII \GRE -- Version \ MS1A: .BLKB 6 .ASCII \ ("The Traveller")\ MS01L = . - MS01 MS02: .ASCII \ Taskbuilt on \ MS2A: .BLKB 21. MS02L = . - MS02 MS03: .ASCII \GRE -- Open error on indirect (@) file, FCS status = \ MS3A: .BLKB 3 .ASCII \ octal\ MS03L = . - MS03 MS04: .ASCII \GRE -- I/O error on command input, FCS status = \ MS4A: .BLKB 3 .ASCII \ octal\ MS04L = . - MS04 MS05: .ASCII \GRE -- Maximum indirect (@) file depth exceeded\ MS05L = . - MS05 MS06: .ASCII \GRE -- Syntax error in indirect (@) filespec\ MS06L = . - MS06 MS07: .ASCII \GRE -- Unknown command line error\ MS07L = . - MS07 MS08: .ASCII \GRE -- Syntax error\ MS08L = . - MS08 MS09: .ASCII \GRE -- Unknown or invalid output switch\ MS09L = . - MS09 MS10: .ASCII \GRE -- No wildcards permitted in output filespec\ MS10L = . - MS10 MS11: .ASCII \GRE -- Error in output filespec, FCS status = \ MS11A: .BLKB 3 .ASCII \ octal\ MS11L = . - MS11 MS12: .ASCII \GRE -- Unknown or invalid input switch\ MS12L = . - MS12 MS13: .ASCII \GRE -- Error in input filespec, FCS status = \ MS13A: .BLKB 3 .ASCII \ octal\ MS13L = . - MS13 MS14: .ASCII \GRE -- Forbidden to search files with this extension\ MS14L = . - MS14 MS15: .ASCII \GRE -- No search string specified\ MS15L = . - MS15 MS16: .ASCII \GRE -- Unbalanced or missing search string quoting characters\ MS16L = . - MS16 MS17: .ASCII \GRE -- Error opening output file, FCS status = \ MS17A: .BLKB 3 .ASCII \ octal\ MS17L = . - MS17 MS18: .ASCII \GRE -- Error opening input file, FCS status = \ MS18A: .BLKB 3 .ASCII \ octal\ MS18L = . - MS18 MS19: .ASCII \GRE -- \ MS19A: .BLKB 9. .ASCII \. search string occurrences in \ MS19B: .BLKB 9. .ASCII \. records in \ MS19C: .BLKB 9. .ASCII \. files\ MS19L = . - MS19 MS20: .ASCII \GRE -- Error finding input file, FCS status = \ MS20A: .BLKB 3 .ASCII \ octal\ MS20L = . - MS20 MS21: .ASCII \GRE -- Error reading input file, FCS status = \ MS21A: .BLKB 3 .ASCII \ octal\ MS21L = . - MS21 MS22: .ASCII \GRE -- Error reading file attributes, FCS status = \ MS22A: .BLKB 3 .ASCII \ octal\ MS22L = . - MS22 MS23: .ASCII \ Input buffer size is \ MS23A: .BLKB 5. .ASCII \. blocks\ MS23L = . - MS23 MS24: .ASCII \GRE -- Incorrect search string quoting characters\ MS24L = . - MS24 MS25: .ASCII \[1m\ MS25L = . - MS25 MS26: .ASCII \[0m\ MS26L = . - MS26 MESG99: .ASCII <14>\***************************************\ .ASCII \***************************************\ MS99L = . - MESG99 SYDEV: .ASCII /SY:/ TIDEV: .ASCII /TI:/ .EVEN .PAGE .SBTTL Block Variables FNDFIL: .BLKW 2 ; Matching file(s) found flag/counter FNMBLK: .BLKB 10. ; Buffer for filename from IO.RAT GLIBUF: .BLKW 6 ; Input file GLUN$ buffer GSUBUF: .BLKB IBFLEN ; Buffer, generic search upcased record IFLBUF: .BLKB IBFLEN ; Buffer for input move mode records IOSTAT: .BLKW 2 ; QIO status block RECRED: .BLKW 2 ; Total records read counter SCRBUF: .BLKB CBFLEN ; Scratch buffer STHITS: .BLKW 2 ; String occurrences counter STRBUF: .BLKB SBFLEN ; Search string buffer .PAGE .SBTTL Variables CNTCTR: .WORD 0 COCNT: COSIZ: .WORD 0 ;LENGTH FOR /CO:NNN SCANS DECVER: .WORD 0 ; Decimal file version numbers flag FNPFLG: .WORD 0 ; Filename header printed flag LINCNT: .WORD 0 ; Record number in current file MATCHR: .WORD 0 ; Address of matching string OFEFLG: .WORD 0 ; Output file already exists flag ORGVER: .WORD 0 ; Original .PARSEd file version number SEALEN: .WORD 0 ; Search string length in bytes SWORD: .WORD 0 WLDFLG: .WORD 0 ; Input file wildcards flag .PAGE .SBTTL .SBTTL Code .SBTTL .PSECT GRECOD, RO, I .SBTTL GREP Entry point ; Load and convert the task's identification GREP: MOV #MS1A, R0 ; Load version field address in R0 MOV R3, R1 ; Get first 3 Rad50 characters CALL $C5TA ; Convert to ASCII MOV R4, R1 ; Get second 3 Rad50 characters CALL $C5TA ; Convert to ASCII ; Load and convert the task's buffer size MOV #MS23A, R0 ; Point at output field MOV #BBCT, R1 ; Load the buffer size in blocks CLR R2 ; Suppress leading zeroes CALL $CBDMG ; Convert binary to decimal magnitude ; Load and convert the task's build time and date MOV #MS2A, R0 ; Point at output field MOV #$DBTS, R1 ; Point at TKB-supplied time/date field CALL $DAT ; Convert date to ASCII MOVB #BK, (R0)+ ; Separate date/time with a " at " MOVB #'a, (R0)+ ; MOVB #'t, (R0)+ ; MOVB #BK, (R0)+ ; MOV #3, R2 ; Convert in format HH:MM:SS CALL $TIM ; Convert time to ASCII ; See if decimal version numbers are in use on this system CLR DECVER ; Assume that they are not .IF DF R$$FEA ; If FEAT$ directive available DIR$ #VERTST ; See if decimal version numbers up CMP $DSW, #IS.CLR ; Is decimal support unavailable? BEQ 10$ ; If so, process it as octal INC DECVER ; Set the decimal version number flag .ENDC ; DF R$$FEA ; Assign LUNs to terminal for I/O and command 10$: DIR$ #ALUNTI ; Assign LUN to terminal for I/O DIR$ #ALUNCM ; Assign LUN to terminal for GCML ; Snoop the terminal type for possible later use DIR$ #GETTTY ; Get terminal type ; Initialize Files-11 services FINIT$ ; Initialize Files-11 services .PAGE .SBTTL GETCMD Get Next Command Line ; Get a command line from the input device GETCMD: MOV #GCLBLK, R0 ; Point at the GCML control block BISB #GE.LC, G.MODE(R0) ; Allow lowercase strings to pass GCML$ ; Get a command line BCC PRSCMD ; If successful, go parse the line ; Error getting command line; see if due to end of file on input MOVB G.ERR(R0), R0 ; Load the GCML error code MOVB F.ERR(R0), R1 ; Load FCS error code for later use CMP R0, #GE.EOF ; End of file on input? BNE 10$ ; If not, go check next case EXST$S #EX$SUC ; Exit with success status ; Not due to EOF; if due to command file problem, exit with error status 10$: CMPB R0, #GE.OPR ; Unable to open/reopen file? BNE 20$ ; If not, go check next case MOV #MS3A, R0 ; Point at output block CALL $CBTMG ; Convert byte to octal magnitude PRINT MS03 ; "Unable to open command (@) file, ..." CALL TTYNAM ; Dump the filename and specs JMP GETCMD ; And go try for another command ; Check to see if there was an I/O error on command input 20$: CMPB R0, #GE.IOR ; I/O error? BNE 30$ ; If not, keep checking MOV #MS4A, R0 ; Point at output block CALL $CBTMG ; Convert byte to octal magnitude PRINT MS04 ; "I/O error on command input, FCS ..." JMP GETCMD ; And go try for another command ; Check to see if there was an overrun on file nesting depth 30$: CMPB R0, #GE.MDE ; Maximum nesting depth exceeded? BNE 40$ ; If not, keep checking cases PRINT MS05 ; "Maximum indirect (@) file depth ..." JMP GETCMD ; And go try for another command ; Check to see if there was a syntax error in the command file name 40$: CMPB R0, #GE.BIF ; Command file name error? BNE 50$ ; If not, handle it as unknown PRINT MS06 ; "Syntax error in indirect (@) ..." JMP GETCMD ; And go try for another command ; Unclassified other error getting command line 50$: PRINT MS07 ; "Unknown error getting command ..." JMP GETCMD ; And go try for another command .PAGE .SBTTL PRSCMD Parse Command Line .SBTTL * General Validation PRSCMD: MOV GCLBLK+G.CMLD, CSIBLK+C.CMLD ; Is the command line empty? BEQ GETCMD ; If so, go try for the next command ; Do first syntax validation; return message and restart on error CSI$1 #CSIBLK, GCLBLK+G.CMLD+2 ; Do first syntax validation BCC 10$ ; And if it looks OK, continue PRINT MS08 ; "Syntax error" JMP GETCMD ; And go try for the next command ; See if the command line is void; if so, go try for another 10$: TST CSIBLK+C.CMLD ; Is the command line void now? BNE 20$ ; If not, keep parsing it JMP GETCMD ; And go try for the next command .PAGE .SBTTL * Output File Processing ; See if an output file was specified; if not, default to TI: 20$: MOV #3, CSIBLK+C.DSDS ; Assume output will be to TI:, and MOV #TIDEV, CSIBLK+C.DSDS+2 ; force that into the CSI DDS BITB #CS.EQU, CSIBLK+C.STAT ; Is the line of the form out=in? BEQ 50$ ; If not, don't CSI for the filename ; Output file specified; now try to parse it for validity CSI$2 #CSIBLK, OUTPUT ; Try to get the output file spec BCC 30$ ; And if successful, proceed PRINT MS09 ; "Unknown or invalid output switch" JMP GETCMD ; And go try for another command ; Check to make sure there was no wildcard in the output spec 30$: BITB #CS.WLD, CSIBLK+C.STAT ; Any wildcards in the output? BEQ 40$ ; If not, keep on going PRINT MS10 ; "No wildcards permitted in output ..." JMP GETCMD ; And go try for another command ; Filespec OK; if no device spec was given, force in SY: 40$: TST CSIBLK+C.DEVD ; Was a devicename specified? BNE 50$ ; If so, go parse it as-is MOV #3, CSIBLK+C.DEVD ; Else load in length and name of MOV #SYDEV, CSIBLK+C.DEVD+2 ; the default device SY: ; .PARSE the output FDB FNB so that we can open it later 50$: MOV #OFLFDB, R0 ; Point at the output file FDB MOV R0, R1 ; Copy the output FDB address into R1 ADD #F.FNB, R1 ; And point at the output FDB FNB MOV #CSIBLK+C.DSDS, R2 ; Point at CSI block dataset descriptor CLR R3 ; Don't use a default filename block CALL .PARSE ; Parse the filename into the FDB FNB MOVB F.ERR(R0), R1 ; Was the .PARSE successful? BPL 60$ ; If so, continue processing MOV #MS11A, R0 ; Point at output block CALL $CBTMG ; Convert byte to octal magnitude PRINT MS11 ; "Error in output filespec, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP GETCMD ; And go try for another command .PAGE .SBTTL * Input File Processing ; Now parse the input filespec, and blow out if it's bad 60$: CLR SWORD ; Clear residual bits in switch word MOVB #CS.INP, CSIBLK+C.TYPR ; Assume we're parsing an out=in/ line BITB #CS.EQU, CSIBLK+C.STAT ; Is the line of the form out=in/? BNE 70$ ; If so, parse an input file MOVB #CS.OUT, CSIBLK+C.TYPR ; Else an in/ line, parse an output file 70$: CSI$2 #CSIBLK,, #SWTABL ; Parse the line in either case BCC 80$ ; If parse was successful, continue PRINT MS12 ; "Unknown or invalid input switch" JMP GETCMD ; And go try for another command ; Filespec OK; if no device spec was given, force in SY: 80$: TST CSIBLK+C.DEVD ; Was a devicename specified? BNE 100$ ; If so, go open it as-is MOV #3, CSIBLK+C.DEVD ; Else load in length and name of MOV #SYDEV, CSIBLK+C.DEVD+2 ; the default device SY: .PAGE .SBTTL * /IDent Processing ; See if the /IDent switch was thrown; if not, bypass this section 100$: BIT #SW.IDN, SWORD ; Was /ID set? BEQ 101$ ; If not, don't identify ; Tell the user about ourself, Don Pardo PRINT MS01 ; "Version vxx.xx" PRINT MS02 ; "Taskbuilt on dd-mmm-yy at xx:xx" PRINT MS23 ; "Input buffer size is x. blocks" JMP GETCMD ; And go back again for more commands .PAGE .SBTTL * Input FDB Setup ; .PARSE input filename into FDB so we can .FIND, checking for errors 101$: MOV #IFLFDB, R0 ; Point at the input file FDB MOV R0, R1 ; Copy the FDB address into R1 ADD #F.FNB, R1 ; And point at the filename block MOV #CSIBLK+C.DSDS, R2 ; Point at the CSI dataset descriptor CLR R3 ; Don't use a default filename block CALL .PARSE ; .PARSE the filename into the FDB MOVB F.ERR(R0), R1 ; Load FCS error code from FDB BPL 110$ ; If .PARSE succeeded, continue MOV #MS13A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS13 ; "Error in input filespec, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP GETCMD ; And go try for another command ; Check for and special case 110$: CLR WLDFLG ; Assume not a special wildcard case BIT #, F.FNB+N.STAT(R0) ; Wildcard name or type? BEQ 130$ ; If not, bypass this section BIT #NB.SVR, F.FNB+N.STAT(R0) ; Wildcarded version number? BNE 130$ ; If so, bypass this section MOV F.FNB+N.FVER(R0), R1 ; Load original version number BEQ 120$ ; If version ;0, go save the data CMP R1, #-1 ; Version ;-1? BNE 130$ ; If not, bypass this section ; Special case exists; set the flag for it and zap the FDB to ;* case 120$: INC WLDFLG ; Set the .FIND special case flag (2) BIS #NB.SVR, F.FNB+N.STAT(R0) ; Force wildcard version number MOV R1, ORGVER ; And save the original version number ; Make sure the specified file extension isn't a forbidden one 130$: CALL EXTCHK ; Check the current file extension BCC 140$ ; And if it's OK, keep processing PRINT MS14 ; "Forbidden to search files with ..." JMP GETCMD ; And go try for the next command .PAGE .SBTTL * Check Search String ; If no search string was specified, tell the user so and try again 140$: BIT #SW.SEA, SWORD ; Was the search switch specified? BEQ 150$ ; If not, error out now MOV #STRBUF, R0 ; Load search string buffer address TSTB (R0) ; Was the string null? BNE 160$ ; If not, continue processing 150$: PRINT MS15 ; "No search string specified" JMP GETCMD ; And go try for another command ; Scan the search string for end null and check for quoting char match 160$: TSTB (R0)+ ; Is this character a null? BNE 160$ ; If not, go check the next one SUB #2, R0 ; Correct the overrun CMP #STRBUF, R0 ; Special one-character case? BEQ 170$ ; If so, give correct error message CMPB STRBUF, (R0) ; Are the quoting characters matched? BEQ 180$ ; If so, continue processing 170$: PRINT MS16 ; "Unbalanced or missing search ..." JMP GETCMD ; And go try for another command ; Make sure that the quoting characters are doublequotes 180$: CMPB STRBUF, #'" ; Quoting characters doublequotes? BEQ 181$ ; If so, continue processing PRINT MS24 ; "Incorrect search string quoting ..." JMP GETCMD ; And go try for another command ; Compute the length of the search string and check that it's nonzero 181$: MOV R0, SEALEN ; Load the terminal byte address SUB #STRBUF+1, SEALEN ; Giving the search string length BNE 190$ ; If it's nonzero, continue PRINT MS15 ; "No search string specified" JMP GETCMD ; And go try for another command .PAGE .SBTTL * Convert String to Uppercase ; Push down search string and conditionally convert it to uppercase 190$: MOV #STRBUF+1, R0 ; Point at the search string buffer MOV SEALEN, R1 ; Load the search string length 200$: MOVB (R0)+, R2 ; Load the next character into R2 BIT #SW.EXA, SWORD ; Exact search specified? BNE 210$ ; If so, bypass this conversion CMP R2, #'z ; Greater than lowercase Z? BHI 210$ ; If so, don't convert it CMP R2, #'a ; Less than lowercase A? BLO 210$ ; If so, don't convert it BIC #40, R2 ; Convert lowercase to uppercase 210$: MOVB R2, -2(R0) ; Push down the converted byte SOB R1, 200$ ; And loop until all converted .PAGE .SBTTL * Open Output File ; Attempt to open the output file for append, exiting on fatal error 215$: OFNB$A #OFLFDB ; Attempt to open existing output file MOVB F.ERR(R0), R1 ; Load the FCS error code byte BPL 230$ ; If successful, bypass create open CMPB R1, #IE.NSF ; Error due to no such file? BEQ 220$ ; If so, continue and create it MOV #MS17A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS17 ; "Error opening output file, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP GETCMD ; And go try for another command ; Output file does not exist; create it, exiting on fatal error 220$: OFNB$W ; Attempt to open new output file MOVB F.ERR(R0), R1 ; Load the FCS error code byte BPL 240$ ; If successful, bypass create open MOV #MS17A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS17 ; "Error opening output file, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP GETCMD ; And go try for another command ; Output file exists; if not a terminal, dump the prefix line to it 230$: BITB #FD.TTY, F.RCTL(R0) ; Is the output device a terminal? BNE 240$ ; If so, don't print anything PUT$ , #MESG99, #MS99L ; Dump FF and line of asterisks ; If output file not a terminal, dump the invoking command line it 240$: BITB #FD.TTY, F.RCTL(R0) ; Is the output device a terminal? BNE REPSCH ; If so, bypass this section PUT$ , GCLBLK+G.CMLD+2, GCLBLK+G.CMLD ; Echo command line .PAGE .SBTTL REPSCH Repetitive Search .SBTTL * Find Next File or Exit REPSCH: CLR FNDFIL ; Zero the files-examined doubleword CLR FNDFIL+2 ; counter CLR RECRED ; Zero the records-read doubleword CLR RECRED+2 ; counter CLR STHITS ; Zero the hits-found doubleword CLR STHITS+2 ; counter MOV #IFLFDB, R0 ; Point at the input file FDB BR 15$ ; And bypass wildcard test first time ; Exit the .FIND loop if the input filespec isn't wildcarded 10$: MOV #IFLFDB, R0 ; Point at the input file FDB BIT #, F.FNB+N.STAT(R0) ; Wildcarded? BEQ 20$ ; If not, exit now ; .FIND on the input file FDB for the next potential input file 15$: MOV R0, R1 ; Copy the FDB address into R1 ADD #F.FNB, R1 ; And point at the filename block CALL .FIND ; Attempt to .FIND the file MOVB F.ERR(R0), R1 ; Check the FDB error byte BPL 30$ ; And if successful, continue processing ; .FIND error; if not IE.NSF (no more files), dump error and loop again CMPB R1, #IE.NSF ; No such file? BEQ 20$ ; If so, go handle it MOV #MS20A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS20 ; "Error finding input file, FCS ..." CALL TTYNAM ; Dump the filename and specs BR 10$ ; And go try for the next file ; No more files; print the run statistics 20$: MOV #MS19A, R0 ; Point at first output field MOV #MS19B, R1 ; Point at second output field MOV #MS19C, R2 ; Point at third output field MOV #9., R3 ; Load field width 21$: CLRB (R0)+ ; Null the first field CLRB (R1)+ ; Null the second field CLRB (R2)+ ; Null the third field SOB R3, 21$ ; And go until all fields nulled MOV #MS19A, R0 ; Point at the output string MOV #STHITS, R1 ; Point at the hits counter 2word CLR R2 ; Suppress leading zeroes CALL $CDDMG ; Convert double to decimal MOV #MS19B, R0 ; Point at the output string MOV #RECRED, R1 ; Point at the record counter 2word CLR R2 ; Suppress leading zeroes CALL $CDDMG ; Convert double to decimal MOV #MS19C, R0 ; Point at the output string MOV #FNDFIL, R1 ; Load the files-found-and-read count CLR R2 ; Suppress leading zeroes CALL $CDDMG ; Convert double to decimal PRINT MS19 ; "Files searched = xxxxx." ; Close the output file and go back for another command CLOSE$ #OFLFDB ; Close the output file JMP GETCMD ; And go try for another command .PAGE .SBTTL * File Validation ; File found; if it has a forbidden extension, ignore it and try again 30$: CALL EXTCHK ; Check the file extension BCS 10$ ; If it's forbidden, try for next file ; Don't inspect our output file (not completely correct, but pretty good) CMP F.FNB+N.FID(R0), OFLFDB+F.FNB+N.FID ; File numbers same? BNE 40$ ; If not, continue processing CMP F.FNB+N.FID+2(R0), OFLFDB+F.FNB+N.FID+2 ; Revision numbers same? BEQ 10$ ; If so, ignore the file and try again .PAGE .SBTTL * Wildcard .FIND Processing ; If and , .FIND again to see ; if this is the right file. .FIND does not handle this case. 40$: TST WLDFLG ; Special wildcard case? BEQ 70$ ; If not, bypass this section ; Copy the input FNB we just used in the .FIND to the auxiliary FNB MOV #IFLFDB+F.FNB, R5 ; Point at the input file FDB FNB MOV #FNDFNB, R4 ; Point at the auxiliary FNB MOV R4, R1 ; And copy that into R1 for .FIND use MOV #S.FNBW, R3 ; Load FNB length in words 50$: MOV (R5)+, (R4)+ ; Copy next word in the FNB SOB R3, 50$ ; And loop until it's all copied ; Set up auxiliary FNB with correct version number and .FIND again MOV ORGVER, N.FVER(R1) ; Load the correct version number BIC #, N.STAT(R1) BIS #, N.STAT(R1) CLR N.NEXT(R1) ; Clear the .FIND next context CALL .FIND ; Attempt to .FIND the file MOVB F.ERR(R0), R1 ; Load the FDB error byte BPL 60$ ; If successful, continue processing ; Unexpected (very) .FIND error; tell user and go try for next file MOV #MS20A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS20 ; "Error finding input file, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP 10$ ; And go try for the next file ; See if the two files are identical; if not, go try for another one 60$: CMP IFLFDB+F.FNB+N.FID, FNDFNB+N.FID ; File numbers same? ; (If so, revisions must be identical) BEQ 70$ ; If so, continue processing JMP 10$ ; If not, go try the next file .PAGE .SBTTL * Open Next File ; Open the file so we can look at it; on failure, try for next file 70$: MOV #, F.OVBS(R0) ; Reset the big buffer size OFID$R ; Open by file-ID MOVB F.ERR(R0), R1 ; Load FCS error code from FDB BPL 80$ ; If successful, continue processing MOV #MS18, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS18 ; "Error opening input file, FCS ..." CALL TTYNAM ; Dump the filename and specs JMP 10$ ; And go try for the next one ; Show that one more file was opened and processed, then continue 80$: ADD #1, FNDFIL+2 ; Bump the files-found-and-read ADC FNDFIL ; doubleword counter .PAGE .SBTTL * Get Next Input Record ; Set up to search the file for the specified string CLR FNPFLG ; Clear filename-printed flag CLR LINCNT ; And zero the current record number ; Get the next input record and check for read errors 90$: GET$ #IFLFDB ; Try to get the next input record MOVB F.ERR(R0), R1 ; Load the FDB error byte BPL 110$ ; If successful, continue processing ; Read error; if IE.EOF, close and return; else warn, close and return CMPB R1, #IE.EOF ; End of file on input? BEQ 100$ ; If so, ignore it and go do next file MOV #MS21A, R0 ; Point at output field CALL $CBTMG ; Convert byte to octal PRINT MS21 ; "Error reading input file, FCS ..." CALL TTYNAM ; Dump the filename and specs 100$: CLOSE$ #IFLFDB ; Close the input file JMP 10$ ; And go try for the next file .PAGE .SBTTL * Pre-Search Setup ; Check record length, and see if match possible; if not, go read again 110$: INC LINCNT ; Increment the current record number ADD #1, RECRED+2 ; Bump the total records read counter ADC RECRED ; doubleword MOV IFLFDB+F.NRBD, R5 ; Load the record length in bytes SUB SEALEN, R5 ; Subtract search string length BMI 90$ ; And if negative, match impossible ; Match is possible. Remove a possible leading formfeed CMPB @IFLFDB+F.NRBD+2, #FF ; Leading formfeed? BNE 216$ ; If not, continue processing INC IFLFDB+F.NRBD+2 ; Bump the record buffer up one byte DEC IFLFDB+F.NRBD ; Drop the record length one byte ; Convert record to uppercase unless /EXact specified 216$: BIT #SW.EXA, SWORD ; Is the /EXact switch set? BNE 115$ ; If so, bypass the conversion MOV IFLFDB+F.NRBD+2, R1 ; Point at the record buffer MOV IFLFDB+F.NRBD, R2 ; Load the record length MOV #GSUBUF, R3 ; Point at the generic search buffer 111$: MOVB (R1)+, R4 ; Load the next input byte BMI 112$ ; If sign bit is set, non-ASCII char CMP R4, #'z ; Greater than lowercase Z? BHI 112$ ; If so, don't convert it CMP R4, #'a ; Less than lowercase A? BLO 112$ ; If so, don't convert it BIC #40, R4 ; Convert lowercase to uppercase 112$: MOVB R4, (R3)+ ; Copy next character to upcased buffer SOB R2, 111$ ; And loop until all converted .PAGE .SBTTL * Search Record for String ; A match may be possible; do a recurrent search looking for one 115$: MOV #GSUBUF, R1 ; Generic search points @ upcased buffer BIT #SW.EXA, SWORD ; Is the /EXact switch set? BEQ 116$ ; If not, don't point at original buffer MOV IFLFDB+F.NRBD+2, R1 ; Exact search, load record start in R1 116$: ADD R1, R5 ; Compute last possible search address 120$: CMP R1, R5 ; Last possible position searched? BHI 90$ ; If so, go get next record MOV R1, R2 ; Copy search start position into R2 MOV #STRBUF, R3 ; Copy search buffer start into R3 MOV SEALEN, R4 ; Copy search buffer length into R4 130$: CMPB (R3), #'? ; Is this a match-all character? BEQ 140$ ; If so, skip the normal compare CMPB (R3), (R2) ; Compare the buffer characters BEQ 140$ ; If a match, then continue looping INC R1 ; Search again starting at next char BR 120$ ; And start search again ; Match is still possible; point at next characters and go examine them 140$: INC R3 ; Point at next search string char INC R2 ; Point at next buffer char SOB R4, 130$ ; And loop until all examined ; We have a match; compute the match base offset for possible later use MOV R1, MATCHR ; Compute matching character offset SUB #GSUBUF, MATCHR ; from generic/upcased buffer base BIT #SW.EXA, SWORD ; Is the /EXact switch set? BEQ 516$ ; If not, we guessed right ADD #GSUBUF, MATCHR ; Correct generic search assumption SUB IFLFDB+F.NRBD+2, MATCHR ; Compute offset from file buffer base ; Bump the hits counter doubleword 516$: ADD #1, STHITS+2 ; Increment the string hits doubleword ADC STHITS ; counter .PAGE .SBTTL * Process Matching Record ; Dump header, line, and pointer lines to the output file as required CALL PUTNAM ; Dump filename and specs if required CALL CRTPRC ; Do CRT processing, if required CALL NMBRIT ; Number the line, if required PUT$ #OFLFDB ; Write the matching record CALL DMPTLN ; Dump pointer line, if required ; All done with this record. Go back and look at another. JMP 90$ ; Go look at next record .PAGE .SBTTL .SBTTL Subroutines .SBTTL .SBTTL $C5OTB Convert R50 Octal to Binary ; $$ CCCCCCCC 5555555555 OOOOOOOO TTTTTTTTTT BBBBBBBBB ; $$$$$$$$ CCCCCCCC 5555555555 OOOOOOOO TTTTTTTTTT BBBBBBBBB ; $$$$$$$$$$ CC CC 55 OO OO TT BB BB ; $$ $$ CC CC 55 OO OO TT BB BB ; $$ $$ CC 55555555 OO OO TT BBBBBBBBB ; $$$$$$$$$ CC 555555555 OO OO TT BBBBBBBBB ; $$$$$$$$$ CC 55 OO OO TT BB BB ; $$ $$ CC 55 OO OO TT BB BB ; $$ $$ CC CC 55 OO OO TT BB BB ; $$$$$$$$$$ CC CC 55 OO OO TT BB BB ; $$$$$$$$ CCCCCCCC 555555555 OOOOOOOO TT BBBBBBBBB ; $$ CCCCCCCC 55555555 OOOOOOOO TT BBBBBBBBB ; $C5OTB - Convert Octal Number in Radix-50 Representation to Binary ; ; This subroutine converts an octal number in Radix-50 representation ; to binary word. ; ; Inputs: R1 - Radix-50 word to be converted ; ; Outputs: R1 - Binary converted word ; R1 is undefined if input is invalid ; ; Register dispositions: R1 destroyed $C5OTB: MOV R3, -(SP) ; Save R3 on the stack MOV R2, -(SP) ; Save R2 on the stack MOV R0, -(SP) ; Save R0 on the stack CLR R3 ; Work in R3 MOV #3, R2 ; Do the following loop once per digit ; Divide-by-50, convert-to-octal, shift-and-bitset conversion loop 10$: CLR R0 ; Zero high word DIV #50, R0 ; Divide by 50 octal SUB #36, R1 ; Subtract R50 0 code from remainder ASH #9., R1 ; Shift result up by 9 bits BIS R1, R3 ; Bitset the next digit in ASH #-3, R3 ; Shift working down by 3 bits MOV R0, R1 ; Copy working back into R1 SOB R2, 10$ ; And loop until 3 digits converted 20$: MOV R3, R1 ; Copy converted word into R1 MOV (SP)+, R0 ; Restore R0 from the stack MOV (SP)+, R2 ; Restore R2 from the stack MOV (SP)+, R3 ; Restore R3 from the stack RETURN ; Return to the caller .PAGE .SBTTL CRTPRC CRT Processing ; CCCCCCCC RRRRRRRRR TTTTTTTTTT PPPPPPPPP RRRRRRRRR CCCCCCCC ; CCCCCCCC RRRRRRRRR TTTTTTTTTT PPPPPPPPP RRRRRRRRR CCCCCCCC ; CC CC RR RR TT PP PP RR RR CC CC ; CC CC RR RR TT PP PP RR RR CC CC ; CC RRRRRRRRR TT PPPPPPPPP RRRRRRRRR CC ; CC RRRRRRRRR TT PPPPPPPPP RRRRRRRRR CC ; CC RR RR TT PP RR RR CC ; CC RR RR TT PP RR RR CC ; CC CC RR RR TT PP RR RR CC CC ; CC CC RR RR TT PP RR RR CC CC ; CCCCCCCC RR RR TT PP RR RR CCCCCCCC ; CCCCCCCC RR RR TT PP RR RR CCCCCCCC ; CRTPRC - Process Record Buffer for CRT Bright Bolding ; ; This subroutine processes the input file record buffer and generates ; a buffer containing bright bolding sequences for DEC_CRT terminals. ; ; Inputs: IFLFDB record buffer ; ; Outputs: None ; ; Register dispositions: All registers used are saved and restored ; If TI: is a DEC_CRT and output is to TI:, then go process the line CRTPRC: TSTB TATLST+1 ; Is the host terminal a DEC_CRT? BEQ 10$ ; If not, return now BITB #FD.TTY, OFLFDB+F.RCTL ; Is the output device a terminal? BNE 20$ ; If so, continue processing ; Not a DEC_CRT or output not to TI:, so copy the input file FDB buffer ; spec to the output file FDB, and return to the caller 10$: MOV IFLFDB+F.NRBD+2, OFLFDB+F.NRBD+2 ; Load record address MOV IFLFDB+F.NRBD, OFLFDB+F.NRBD ; Load the record length RETURN ; Return to the caller ; Build a new buffer with CRT control sequences in it 20$: CALL $SAVAL ; Save general registers R0 - R5 ; Load everything up to the matching string MOV IFLFDB+F.NRBD+2, R0 ; Point at current input buffer MOV #SCRBUF, R1 ; Point at the scratch buffer MOV R1, OFLFDB+F.NRBD+2 ; And copy buffer address to output FDB MOV MATCHR, R2 ; Load offset to match base BEQ 35$ ; If zero offset, bypass first copy 30$: MOVB (R0)+, (R1)+ ; Copy a byte to the scratch buffer SOB R2, 30$ ; And loop until that's copied ; Insert the CRT special effects string 35$: MOV #MS25, R2 ; Point at the special effect string MOV #MS25L, R3 ; Load special effect string length 40$: MOVB (R2)+, (R1)+ ; Copy next byte into buffer SOB R3, 40$ ; And loop until all copied ; Copy in the matching string itself MOV SEALEN, R2 ; Load match string length 50$: MOVB (R0)+, (R1)+ ; Copy a byte to the scratch buffer SOB R2, 50$ ; And loop until all copied ; Insert the second special CRT string MOV #MS26, R2 ; Point at the special effect string MOV #MS26L, R3 ; Load special effect string length 60$: MOVB (R2)+, (R1)+ ; Copy next byte into buffer SOB R3, 60$ ; And loop until all copied ; Append the rest of the buffer, carefully checking for the end since ; we may be at the end of the buffer already MOV IFLFDB+F.NRBD+2, R2 ; Load input buffer base address ADD IFLFDB+F.NRBD, R2 ; And point at first byte after it 70$: CMP R0, R2 ; Has last byte been copied yet? BHIS 80$ ; If so, exit the copy loop MOVB (R0)+, (R1)+ ; Copy a byte to the scratch buffer BR 70$ ; And go loop for another byte ; Correct the output file buffer length, then return to caller 80$: SUB OFLFDB+F.NRBD+2, R1 ; Calculate buffer length MOV R1, OFLFDB+F.NRBD ; Load buffer length into FDB RETURN ; And return to the caller .PAGE .SBTTL DMPTLN Dump Pointer Line ; DDDDDDDD MMM MMM PPPPPPPPP TTTTTTTTTT LL NN NN ; DDDDDDDD MMM MMM PPPPPPPPP TTTTTTTTTT LL NN NN ; DD DD MMMM MMMM PP PP TT LL NNNN NN ; DD DD MMMM MMMM PP PP TT LL NNNN NN ; DD DD MM MM MM PPPPPPPPP TT LL NN NN NN ; DD DD MM MM MM PPPPPPPPP TT LL NN NN NN ; DD DD MM MM PP TT LL NN NNNN ; DD DD MM MM PP TT LL NN NNNN ; DD DD MM MM PP TT LL NN NNN ; DD DD MM MM PP TT LL NN NNN ; DDDDDDDD MM MM PP TT LLLLLLLLLL NN NN ; DDDDDDDD MM MM PP TT LLLLLLLLLL NN NN ; DMPTLN - Dump Pointer Line ; ; This subroutine generates and dumps a pointer line underneath ; the output line containing the located record. ; ; Inputs: IFLFDB record buffer ; MATCHR - Match character offset from buffer base ; SEALEN - Search string length ; SWORD - CSI switch word ; ; Outputs: OFLFDB+F.NRBD - Output file FDB buffer length ; OFLFDB+F.NRBD+2 - Output file FDB buffer address ; ; Register dispositions: All registers used are saved and restored ; ; Variable dispositions: SCRBUF buffer destroyed ; If pointer dumps are not required, return to the caller DMPTLN: BIT #SW.POI, SWORD ; Is a pointer line desired? BNE 10$ ; If so, go produce it RETURN ; Else return to the caller ; Save registers, then prepend 8 blanks if line numbering is active 10$: CALL $SAVAL ; Save general registers R0 - R5 MOV #SCRBUF, R1 ; Load scratch buffer address MOV R1, OFLFDB+F.NRBD+2 ; And load it to the output file FDB BIT #SW.LIN, SWORD ; Is line numbering active? BEQ 15$ ; If not, don't prepend blanks MOV #8., R0 ; Load 8 blanks 11$: MOVB #BK, (R1)+ ; Prepend a blank SOB R0, 11$ ; And loop until all prepended ; Copy input to scratch buffer, replacing printing characters with ; blanks, until start of match string 15$: MOV IFLFDB+F.NRBD+2, R0 ; Load input file buffer address MOV MATCHR, R2 ; Load match string offset into R2 BEQ 35$ ; If zero, don't copy anything 20$: MOVB (R0)+, (R1) ; Copy the character CMPB (R1), #BK ; Control character or blank? BLOS 30$ ; If so, leave it MOVB #BK, (R1) ; Else blank the character 30$: INC R1 ; Point at the next character SOB R2, 20$ ; And loop until it's all blanked ; Check for and process the special single-character case 35$: MOVB #'^, (R1)+ ; Load the special pointer there CMP SEALEN, #1 ; One character string? BEQ 60$ ; If so, go dump it now ; Otherwise, build the <----> pointer line MOVB #'<, -1(R1) ; Replace it with the open bracket MOV SEALEN, R2 ; Load the search string length SUB #2, R2 ; Correct for leading-trailing brackets BEQ 50$ ; If two char string, don't fill it 40$: MOVB #'-, (R1)+ ; Stick in a filling hyphen SOB R2, 40$ ; And continue doing that until full 50$: MOVB #'>, (R1)+ ; Terminate hyphens with trailing ">" ; Dump the line with the pointers to the output file and return 60$: SUB OFLFDB+F.NRBD+2, R1 ; Calculate the record length MOV R1, OFLFDB+F.NRBD ; And load it into the output FDB PUT$ #OFLFDB ; And dump the pointer line to output RETURN ; And return to the caller .PAGE .SBTTL EXTCHK Input File Extension Check ; EEEEEEEEEE XX XX TTTTTTTTTT CCCCCCCC HH HH KK KK ; EEEEEEEEEE XX XX TTTTTTTTTT CCCCCCCC HH HH KK KK ; EE XX XX TT CC CC HH HH KK KK ; EE XX XX TT CC CC HH HH KK KK ; EEEEEEEE XXXX TT CC HHHHHHHHHH KK KK ; EEEEEEEE XXXX TT CC HHHHHHHHHH KK KK ; EE XX XX TT CC HH HH KKK KK ; EE XX XX TT CC HH HH KKK KK ; EE XX XX TT CC CC HH HH KK KK ; EE XX XX TT CC CC HH HH KK KK ; EEEEEEEEEE XX XX TT CCCCCCCC HH HH KK KK ; EEEEEEEEEE XX XX TT CCCCCCCC HH HH KK KK ; EXTCHK - Search Invalid File Extension Table for File Extension ; ; This subroutine searches the invalid file extension table to see if ; one of the entries matches the extension of the input file. ; ; Inputs: IFLFDB+F.FNB+N.FTYP - FDB file extension name ; ; Outputs: Carry clear if not found ; Carry set if found ; ; Register dispositions: All registers used are saved and restored ; Set up to search the invalid extension table for this input extension EXTCHK: MOV R0, -(SP) ; Save R0 on the stack MOV #IEXTBL, R0 ; Point at invalid extension table ; Search through the table until we find the extension or the table ends 10$: TST (R0) ; Is this entry table end? BEQ 20$ ; If it's table end, exit search loop CMP (R0)+, IFLFDB+F.FNB+N.FTYP ; Invalid extension? BNE 10$ ; If not, go look at next one SEC ; Show failure to the caller ; Return to the caller with carry clear or set, as appropriate 20$: MOV (SP)+, R0 ; Restore R0 from the stack RETURN ; Return .PAGE .SBTTL NMBRIT Number Output Line ; NN NN MMM MMM BBBBBBBBB RRRRRRRRR IIIIIIII TTTTTTTTTT ; NN NN MMM MMM BBBBBBBBB RRRRRRRRR IIIIIIII TTTTTTTTTT ; NNNN NN MMMM MMMM BB BB RR RR II TT ; NNNN NN MMMM MMMM BB BB RR RR II TT ; NN NN NN MM MM MM BBBBBBBBB RRRRRRRRR II TT ; NN NN NN MM MM MM BBBBBBBBB RRRRRRRRR II TT ; NN NNNN MM MM BB BB RR RR II TT ; NN NNNN MM MM BB BB RR RR II TT ; NN NNN MM MM BB BB RR RR II TT ; NN NNN MM MM BB BB RR RR II TT ; NN NN MM MM BBBBBBBBB RR RR IIIIIIII TT ; NN NN MM MM BBBBBBBBB RR RR IIIIIIII TT ; NMBRIT - Prepend Line Number to Output Buffer ; ; This subroutine prepends the current line number to the output ; buffer and corrects the output file FDB to reflect this. ; ; Inputs: OFLFDB+F.NRBD - Length of output buffer ; OFLFDB+F.NRBD+2 - Address of output buffer ; SWORD - CSI switch word ; ; Outputs: OFLFDB+F.NRBD - Length of output buffer ; OFLFDB+F.NRBD+2 - Address of output buffer ; ; Register dispositions: All registers used are saved and restored ; ; Variable dispositions: SCRBUF destroyed ; If line numbering is not active, just return NMBRIT: BIT #SW.LIN, SWORD ; Is line numbering desired? BNE 10$ ; If so, go number the line RETURN ; Return to the caller ; Save all registers 10$: CALL $SAVAL ; Save general registers R0 - R5 ; Push the old buffer up into SCRBUF first, since buffer may be SCRBUF MOV OFLFDB+F.NRBD+2, R1 ; Load output buffer base address ADD OFLFDB+F.NRBD, R1 ; And point at first byte after it MOV #SCRBUF, R0 ; Point at the scratch buffer ADD OFLFDB+F.NRBD, R0 ; Point at equivalent in scratch buffer ADD #8., R0 ; Leave space for line number and spaces 20$: MOVB -(R1), -(R0) ; Copy a byte to the scratch buffer CMP R0, #SCRBUF ; Done copying yet? BHI 20$ ; If not, go copy more ; Prepend the line number and two trailing spaces to the buffer MOV LINCNT, R1 ; Load the current record number MOV #<27000!10.>, R2 ; 5 wide decimal blank-led field CALL $CBTA ; Convert binary to ASCII MOVB #BK, (R0)+ ; And add three trailing blanks MOVB #BK, (R0)+ ; MOVB #BK, (R0)+ ; MOV #SCRBUF, OFLFDB+F.NRBD+2 ; Load new output buffer address ADD #8., OFLFDB+F.NRBD ; And correct the buffer length RETURN ; And return to the caller .PAGE .SBTTL PUTNAM Write Filename Buffer .SBTTL TTYNAM Dump Filename Buffer ; * ** * * ** * * ** * NN NN AAAA MMM MMM ; ** **** ** ** **** ** ** **** ** NN NN AAAA MMM MMM ; ******** ******** ******** NNNN NN AA AA MMMM MMMM ; ****** ****** ****** NNNN NN AA AA MMMM MMMM ; ** ** ** NN NN NN AA AA MM MM MM ; ********** ********** ********** NN NN NN AA AA MM MM MM ; ********** ********** ********** NN NNNN AAAAAAAAAA MM MM ; **** **** **** NN NNNN AAAAAAAAAA MM MM ; ****** ****** ****** NN NNN AA AA MM MM ; ** ** ** ** ** ** ** ** ** NN NNN AA AA MM MM ; ** ** ** ** ** ** ** ** ** NN NN AA AA MM MM ; * ** * * ** * * ** * NN NN AA AA MM MM ; PUTNAM - Write FDB Filename to Output File ; TTYNAM - Dump FDB Filename to Owning Terminal ; ; This subroutine builds a buffer containing the fully specified ; filename from the FDB pointed to by R0, then either dumps it to ; TI: or writes it to the output file. ; ; TTYNAM inputs: R0 - Pointer to FDB ; PUTNAM inputs: None ; ; Outputs: None ; ; Register dispositions: All registers used are saved and restored ; Entry to dump file name and FID to terminal TTYNAM: CALL $SAVAL ; Save general registers R0 - R5 CLR R5 ; Flag terminal output entry MOV #SCRBUF, R2 ; Point at the scratch buffer MOV #" , (R2)+ ; Blank start of buffer corresponding MOV #" , (R2)+ ; to the prefix text "GRE -- " MOV #" , (R2)+ ; MOVB #BK, (R2)+ BR COMNAM ; And hit the common entry point ; Entry to dump input file name and FID to output file PUTNAM: TST FNPFLG ; Has filename header line been printed? BEQ 10$ ; If not, go print it RETURN ; Return to the caller 10$: CALL $SAVAL ; Save general registers R0 - R5 MOV #SCRBUF, R2 ; Point at the scratch buffer MOV #"Fi, (R2)+ ; Prefix the filename with "File " MOV #"le, (R2)+ ; MOVB #BK, (R2)+ ; MOV SP, R5 ; Flag file output entry MOV #IFLFDB, R0 ; Point at input file FDB MOV SP, FNPFLG ; Show that the header line's printed ; Common code to both TTYNAM and PUTNAM ; ; Get information on specified file's LUN, then assign info LUN to it COMNAM: MOVB F.LUN(R0), GLINFO+G.LULU ; Load up the file LUN number DIR$ #GLINFO ; Get LUN information on it MOV GLIBUF+G.LUNA, ALUNAQ+A.LUNA ; Load the device name MOVB GLIBUF+G.LUNU, ALUNAQ+A.LUNU ; Load the device number DIR$ #ALUNAQ ; And assign info LUN to it ; Set up and execute the ACP QIO DPB to get directory name information ADD #F.FNB, R0 ; Point at the file's filename block MOV R0, GETNAM+Q.IOPL ; Copy FDB pointer into ACP QIO DPB ADD #N.DID, GETNAM+Q.IOPL ; Make it point at file's directory FID DIR$ #GETNAM ; And ask the ACP for filename info MOVB IOSTAT, R1 ; Load the I/O status block BPL 5$ ; If QIO succeeded, proceed MOV #MS22A, R0 ; Point at the output field CALL $CBTMG ; Convert byte to octal magnitude PRINT MS22 ; "Error reading file attributes, ..." RETURN ; Return to caller, what else can we do? ; Load and convert the device name and number into the output buffer 5$: MOV R0, R4 ; Copy the FDB pointer into R4 MOV R2, R0 ; Load the output buffer pointer MOVB GLIBUF+G.LUNA, (R0)+ ; Load the real devicename, 1st char MOVB GLIBUF+G.LUNA+1, (R0)+ ; Load the real devicename, 2nd char MOVB GLIBUF+G.LUNU, R1 ; Load the real unit number byte CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert byte to octal magnitude MOVB #':, (R0)+ ; And trail a colon after it ; Load and convert the directory name or number, assuming it's named MOVB #'[, (R0)+ ; Load a leading open bracket MOV R0, -(SP) ; Save the output pointer on the stack MOV FNMBLK, R1 ; Load the first filename word CALL $C5TA ; Convert Radix-50 to ASCII MOV FNMBLK+2, R1 ; Load the second filename word CALL $C5TA ; Convert Radix-50 to ASCII MOV FNMBLK+4, R1 ; Load the third filename word CALL $C5TA ; Convert Radix-50 to ASCII 10$: CMPB -(R0), #BK ; Was that last character a blank? BEQ 10$ ; If so, strip it and look again INC R0 ; Correct undershoot MOVB #'], (R0)+ ; Trail a closing bracket after it MOV R0, R3 ; Save the output pointer in R3 ; Now see if the directory is really an octal UFD spec; if so, handle it MOV (SP), R0 ; Restore the earlier buffer pointer CALL $COTB ; Convert octal to binary MOV R3, R0 ; Restore the final output pointer CMPB R2, #'] ; Did we terminate on the close bracket? BNE 11$ ; If not, it's named, so bypass UFD MOV (SP), R0 ; Restore the earlier buffer pointer MOV FNMBLK, R1 ; Load the first filename word CALL $C5OTB ; Convert Radix-50 to octal CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert byte to octal magnitude MOVB #',, (R0)+ ; Separate group and member with "," MOV FNMBLK+2, R1 ; Load the second filename word CALL $C5OTB ; Convert Radix-50 to octal CLR R2 ; Suppress leading zeroes CALL $CBTMG ; Convert byte to octal magnitude MOVB #'], (R0)+ ; Close the brackets 11$: TST (SP)+ ; Pop the buffer pointer off the stack ; Load and convert the filename into the output buffer MOV N.FNAM(R4), R1 ; Load the first filename word CALL $C5TA ; Convert Radix-50 to ASCII MOV N.FNAM+2(R4), R1 ; Load the second filename word CALL $C5TA ; Convert Radix-50 to ASCII MOV N.FNAM+4(R4), R1 ; Load the third filename word CALL $C5TA ; Convert Radix-50 to ASCII 20$: CMPB -(R0), #BK ; Was that last character a blank? BEQ 20$ ; If so, strip it and look again INC R0 ; Correct undershoot MOVB #'., (R0)+ ; And trail a decimal point after it ; Load and convert the file extension into the output buffer MOV N.FTYP(R4), R1 ; Load the file extension CALL $C5TA ; And convert Radix-50 to ASCII 3$: CMPB -(R0), #BK ; Was that last character a blank? BEQ 3$ ; If so, strip it and look again INC R0 ; Correct undershoot MOVB #';, (R0)+ ; And trail a semicolon after it ; Load and convert the file version number into the output buffer MOV N.FVER(R4), R1 ; Load the file version number MOV #<30000!8.>, R2 ; Assume octal version numbers TST DECVER ; Decimal version numbers in use? BEQ 6$ ; If not, don't use them MOV #<24000!10.>, R2 ; Wrong, set decimal version numbers 6$: CALL $CBTA ; Convert binary to ASCII MOVB #BK, (R0)+ ; Trail a space after it ; Load and convert the FID into the output buffer MOVB #BK, (R0)+ ; Prefix FID doubleword with " FID " MOVB #'F, (R0)+ ; MOVB #'I, (R0)+ ; MOVB #'D, (R0)+ ; MOVB #BK, (R0)+ ; MOVB #'(, (R0)+ ; Load an open paren before the FID MOV N.FID(R4), R1 ; Load the FID first word CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert binary to octal magnitude MOVB #',, (R0)+ ; Load a separating comma MOV N.FID+2(R4), R1 ; Load the FID second word CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert binary to octal magnitude MOVB #'), (R0)+ ; Trail a close paren after it ; Dump the buffer on the output file if required SUB #SCRBUF, R0 ; Calculate the buffer length TST R5 ; Dumping to terminal or file? BEQ 30$ ; If zero, dump to terminal MOV R0, R1 ; Because R0 will be destroyed by PUT PUT$ #OFLFDB, #MS00, #MS00L ; Dump a preceding blank line PUT$ , #SCRBUF, R1 ; Dump the filename to output file PUT$ , #MS00, #MS00L ; Dump a trailing blank line INC FNPFLG ; Show that the header's been printed RETURN ; And return to the caller ; Else dump the buffer on the terminal 30$: MOV #SCRBUF, TTYOUT+Q.IOPL ; Point at the prefixed buffer MOV R0, TTYOUT+Q.IOPL+2 ; Load the buffer length DIR$ #TTYOUT ; Print the buffer on the terminal RETURN ; And return to the caller .END GREP