; MLIST.ASM - V5.0 ; MULTIPLE FILE LIST UTILITY ; by Keith Petersen, W8SDZ ; (revised 7/7/81) ; ;NOTE: REQUIRES 'MAC' AND SEQIO.LIB TO ASSEMBLE ; ;This program lists any size ASCII file by name, reading ;up to 16k of the file into memory at one time, in order ;to minimize disk activity during printout. The output ;is "filtered" to trap out all control characters other ;than CR, LF, and TAB. If optional 'P' command used, ;output also goes to list device (this is especially ;useful under submit). Any form feeds in the file are ;passed on to the list device. ; ;Allows listing of multiple files by using normal CP/M ;ambiguous file names. Before each file is printed, the ;FILENAME.TYPE is displayed. If a non-printable file is ;encountered (such as .COM or .OBJ), skips to next file. ;If a file has 'Q' as 2nd char. of filetype, prints msg ;saying if file doesn't print correctly, use TYPESQ. ; ;Commands: MLIST B:MYFILE.DOC ;lists specified file ; MLIST *.ASM ;lists all ASM files ; MLIST *.ASM P ;same, also goes to list device ; ;Use CTL-S to pause, CTL-X to skip to next file, CTL-C to abort. ;Other characters are ignored. ; ;This program allows CP/M 1.4 users to have protected ;ASCII files on a remote system, provided that the CCP ;'REN' (rename) and 'TYPE' functions have been changed ;to some other characters and MLIST.COM has been renamed ;to TYPE.COM. To protect a file, rename it so the last ;character of the file type is #. Example: MYFILE.AS# ; ;CP/M 2.x users may use 'TAG.COM' to set the f1' attribute ;of a file, which will prevent this program from listing it. ; ;Modifications/revisions, listed in reverse order ;to minimize reading time: ; ;07/07/71 Ver 5.0 - Added test for possible squeezed file. ; (KBP) ; ;01/12/81 Added code to allow passing form feeds to list ; output. Added trap for DEL (RUBOUT). (KBP) ; ;01/10/81 Added 'P' option so files can be printed on the ; list device. This now allows selective printing ; of hard copy while running under submit. (KBP) ; ;01/01/81 Added CTL-X skip to next file, direct console ; output with tab expansion and control character ; filter. (KBP) ; ;09/21/80 Added test for SYS files, moved TAG test, ; removed extra OPEN of file. (KBP) ; ;09/20/80 Added ILPRT routine, revised messages, added new ; abort routine, added CP/M 2.x f1' protect test, ; cleaned up file. (KBP) ; ;09/09/80 Revised check for '.COM' and '.OBJ' files so ; during attempt to list multiple files these ; would not abort the routine. Modified to ; issue an error message and continue with the ; next valid file. Added check for '#' character ; as the last character in the file type indicat- ; ing the file was not for distribution. Routine ; issues an error message and continues. Added ; check for 'first time flag' to exit routine so ; if no file is found meeting the requested ; parameters, '++NOT FOUND++' is issued to the ; console. NOTE: This required modifying the manner ; in which 'MFFLG1' was handled. By Jim Seymour ; ;05/27/80 Revised to abort on attempting to ; list a CP/M .COM file. By Thomas Churbuck ; FORMF EQU 0CH ;FORM FEED CHAR. ; ORG 100H ; MACLIB SEQIO ;DEFINE MACRO LIBRARY ; START: JMP START2 ;JMP AROUND IDENT DB 'MLIST.COM ver 5.0 07/07/81' ; START2: LXI H,0 DAD SP ;GET OLD STACK SHLD STACK ;SAVE IT LXI SP,STACK ;SET NEW STACK LHLD 1 ;POINT TO CP/M'S JMP TABLE LXI D,3 ;READY FOR ADD DAD D ;HL=CONSTAT SHLD CSTSC+1 ;MODIFY CALL ADRS DAD D ;HL=CONIN SHLD CIC+1 ;MODIFY CALL ADRS DAD D ;HL=CONOUT SHLD VCONOT+1 ;MODIFY CALL ADRS DAD D ;HL=LISTOUT SHLD VLIST+1 ;MODIFY CALL ADRS CALL ILPRT ;PRINT: DB 'MLIST ver 5.0 - Multiple file lister',CR,LF DB 'CTL-S pauses, CTL-X skips to next file, CTL-C aborts',0 LDA FCB2+1 ;GET OPTION, IF ANY STA PFLAG ;SAVE FOR LATER LDA FCB+1 CPI ' ' ;FILENAME THERE? JNZ MORE ;YES, SKIP ERROR EXIT CALL ILPRT ;PRINT: DB 'Usage: MLIST [drive:] [P]' DB CR,LF,CR,LF DB ' < > = required, [ ] = optional, P = printer' DB CR,LF DB ' Ambiguous file names may be used.',0 JMP EXIT ; ;Get file name ; MORE: LXI SP,STACK ;ASSURE VALID STACK XRA A ;ZERO STA TABCOL ;..THE COLUMN COUNTER CALL MFNAME ;GET NEXT FILE NAME JNC CKFIL ;ANOTHER FILE FOUND, PRINT IT LDA MFFLG1 ;NOTHING FOUND, CHECK... ORA A ;... FIRST TIME FLAG JZ DONE ;AT LEAST ONE WAS FOUND CALL ILPRT ;PRINT: DB '++FILE NOT FOUND++',0 JMP EXIT ; DONE: CALL ILPRT ;PRINT: DB 'DONE',0 JMP EXIT ; ;Check for file protected by CP/M 2.x f1' attribute ; CKFIL: LDA MFCUR+1 ;POINT TO TAG FILE ATTR ANI 80H ;IS IT TAGGED? JZ CKFIL2 ;IF NOT, CONTINUE ; PROXIT: CALL ILPRT ;PRINT: DB '++FILE NOT FOR DISTRIBUTION, SORRY++',0 JMP MORE ;SEE IF ANOTHER ; CKFIL2: LDA MFCUR+10 ;POINT TO SYS FILE ATTR ANI 80H ;IS IT SYS? JZ MOVNAM ;IF NOT, CONTINUE JMP PROXIT ;SYS FILE, CAN'T PRINT IT ; ;Move filename from FCB+1 to FNAME MOVNAM: LXI H,FCB+1 LXI D,FNAME MVI B,8 CALL MOVER ;Move filetype from FCB+9 to FNAME+9 LXI H,FCB+9 LXI D,FNAME+9 MVI B,3 CALL MOVER ;Print name of file being listed CALL ILPRT ;PRINT: DB CR,LF,'--> LISTING FILE: ' FNAME: DB 'XXXXXXXX.XXX' DB CR,LF,0 ; ;Define source file: ; ; INFILE = Input file mode ; DISKIN = Internal name ; (NUL) = Default disk drive ; 1 = First default name (TFCB) ; (NUL) = " " type ; 16384 = Buffer size ; DSKBUF = Disk buffer area ; FILE INFILE,DISKIN,,1,,16384,DSKBUF ; ;Check for file protected by a '#' as the last ;character in the filetype (i.e. MYFILE.AS#). ; LXI H,FCB+11 ;POINT TO LAST CHAR IN FCB MOV A,M ;GET IT ANI 7FH ;STRIP CP/M 2.x ATTR CPI '#' ;PROTECTED FILE? JZ PROXIT ;PROTECTED FILE, EXIT WITH MSG ; ;Check for .COM file, which can't be printed ; CPI 'M' ;WAS LAST CHAR AN 'M'? JNZ OBJCHK ;IF NOT, CHK FOR '.OBJ' TYPE DCX H MOV A,M ;CHK NEXT ANI 7FH ;STRIP CP/M 2.x ATTR CPI 'O' ;AN 'O'? JNZ SQCHK ;IF NOT IT'S OK TO PRINT DCX H MOV A,M ;WAS 'O', CHK NEXT CHAR ANI 7FH ;STRIP CP/M 2.x ATTR CPI 'C' ;'C' AS IN '.COM'? JNZ SQCHK ;IF NOT, IT'S OK TO PRINT CALL ILPRT ;PRINT: DB '++CAN''T LIST A .COM FILE++',0 JMP MORE ;MORE TO PRINT? ; ;Check for .OBJ file, which can't be printed ; OBJCHK: CPI 'J' ;WAS LAST CHAR AN 'J' ? JNZ SQCHK ;IF NOT, OK TO LIST DCX H MOV A,M ;MIGHT BE '.OBJ', CHK NEXT CHR ANI 7FH ;STRIP CP/M 2.x ATTR CPI 'B' ;IS IT A 'B'? JNZ SQCHK ;IF NOT, LIST DCX H MOV A,M ;WAS, CHK FIRST CHAR ANI 7FH ;STRIP CP/M 2.x ATTR CPI 'O' ;'O' AS IN '.OBJ'? JNZ SQCHK ;IF NOT, PRINT THE FILE, IF SO CALL ILPRT ;PRINT: DB '++CAN''T LIST AN .OBJ FILE++',0 JMP MORE ;MORE TO PRINT? ; ;Check for possible 'squeezed' file, which will not print ; SQCHK: LDA FCB+10 ;GET SECOND CHAR OF FILETYPE ANI 7FH ;STRIP ATTRIBUTE CPI 'Q' ;THIS MAY BE SQUEEZED FILE JNZ READLP ;NOT SQUEEZED CALL ILPRT ;PRINT: DB 'NOTE: If this file doesn''t ' DB 'print correctly, try TYPESQ.',CR,LF DB 'Most files with "Q" as 2nd char. ' DB 'of filetype are squeezed.',CR,LF,CR,LF,0 ; ;Write the file to console ; READLP: GET DISKIN ;GET CHARACTER FROM FILE CPI EOF ;END OF FILE? JZ MORE ;YES, MORE FILES TO PRINT? CALL TYPE ;SEND CHAR TO CONSOLE CALL CSTS ;KEY PRESSED? ORA A CNZ CKKB ;CHECK WHAT KEY JMP READLP ; ;Get keyboard character and check for command ; CKKB: CALL CI ;GET CHAR CPI 'S'-40H ;PAUSE? CZ CI ;YES, GET NEXT CHAR CPI 'C'-40H ;ABORT? JZ EXITA ;YES, PRINT ABORT MSG, EXIT CPI 'X'-40H ;SKIP? RNZ ;NO, CONTINUE LISTING CALL ILPRT ;PRINT: DB CR,LF,'++SKIPPING TO NEXT FILE++',0 JMP MORE ;SKIP TO NEXT FILE ; ;Get console status from CBIOS ; CSTS: PUSH B PUSH D PUSH H CSTSC: CALL $-$ ;CHANGED BY INIT POP H POP D POP B RET ;FROM "CSTS" ; ;Get console input from CBIOS ; CI: PUSH B PUSH D PUSH H CIC: CALL $-$ ;CHANGED BY INIT POP H POP D POP B RET ;FROM "CI" ; ;Inline print routine ; ILPRT: CALL CRLF ;TURN UP A NEW LINE XTHL ;SAVE HL, GET MSG ; ILPLP: MOV A,M ;GET CHAR CALL TYPE ;OUTPUT IT INX H ;POINT TO NEXT MOV A,M ;TEST ORA A ;..FOR END JNZ ILPLP CALL CRLF ;TURN UP A NEW LINE XTHL ;RESTORE HL, RET ADDR RET ;RET PAST MSG ; ;Turn up a new line ; CRLF: MVI A,CR ;GET A CARRIAGE RETURN CALL TYPE MVI A,LF ;GET A LINE FEED AND FALL INTO 'TYPE' ; ;Type character in A to console (with tab expansion). ;This is done via direct CBIOS call to prevent CP/M ;from evaluating input commands. Output also goes to ;list device if 'P' option was specified. ; TYPE: PUSH B PUSH D PUSH H ANI 7FH ;STRIP PARITY BIT OF CHAR CPI 7FH ;DEL (RUBOUT) ? JZ TYPRET ;YES, IGNORE IT MOV C,A ;CHAR TO C FOR OUTPUT ROUTINE CPI TAB ;TAB CHAR? JNZ TYPE2 ;NO, SKIP TAB STUFF ; TYPTAB: MVI A,' ' ;GET A SPACE CALL TYPE ;PRINT IT LDA TABCOL ;GET PRESENT COLUMN ANI 7 ;8 CHAR BOUNDRY? JNZ TYPTAB ;NO, OUTPUT ANOTHER SPACE JMP TYPRET ;DONE WITH TAB EXPANSION ; ;Filter out control characters to ;prevent garbage during view of file ; TYPE2: CPI ' ' ;SPACE OR ABOVE? JNC CONOUT ;YES, GO OUTPUT IT CPI FORMF ;FORM FEED? JZ TYPLST ;YES, SEND TO LIST ONLY CPI CR ;CARRIAGE RETURN? JZ CONOUT ;YES, GO OUTPUT IT CPI LF ;LINE FEED? JNZ TYPRET ;NO, IGNORE CHARACTER ; ;Call direct to CBIOS console output ; CONOUT: PUSH B ;IN CASE CBIOS CLOBBERS IT VCONOT: CALL $-$ ;ADDR FILLED IN BY 'INIT' POP B ;GET CHAR BACK ; ;Update column used in tab expansion MOV A,C ;GET CHAR CPI CR ;CARRIAGE RETURN? JNZ TYPNCR ;NO, SKIP COLUMN ZERO STUFF XRA A ;GET A ZERO STA TABCOL ;RESET COLUMN NR. JMP TYPLST ;EXIT ; TYPNCR: CPI ' ' ;CTL CHAR? JC TYPLST ;..NO CHANGE IN COL LDA TABCOL ;GET COLUMN NR. INR A ;ADD ONE STA TABCOL ;SAVE NEW COUNT ; TYPLST: LDA PFLAG ;GET PRINT FLAG CPI 'P' ;PRINT REQUESTED? CZ LIST ;FROM C REG ; TYPRET: POP H POP D POP B RET ; LIST: PUSH B ;SAVE REGS PUSH D PUSH H VLIST: CALL $-$ ;MODIFIED BY INIT POP H POP D POP B RET ; ;Move (B) bytes from (HL) to (DE) ; MOVER: MOV A,M STAX D INX H INX D DCR B JNZ MOVER RET ; EXITA: CALL ILPRT ;PRINT: DB CR,LF,'++ABORTED++',0 ; EXIT: LXI D,80H ;SET DMA ADDRESS TO NORMAL MVI C,STDMA CALL BDOS LHLD STACK ;GET OLD STACK SPHL ;RESTORE IT RET ;RETURN TO CP/M ; ;Multi-file access subroutine. Allows processing ;of multiple files (i.e. *.ASM) from disk. This ;routine builds the proper name in the FCB each ;time it is called. Carry is set if no more names ;can be found. The routine is commented in Pseudo ;Code, each Pseudo Code statement is in <<...>> ; ;<> MFNAME: MVI C,STDMA LXI D,80H CALL BDOS XRA A STA FCBEXT STA FCBRNO ;<> LDA MFFLG1 ORA A JZ MFN01 ;<> LXI H,FCB LXI D,MFREQ MVI B,12 CALL MOVER LDA FCB STA MFCUR ;SAVE DISK IN CURR FCB ;<> MVI C,SRCHF LXI D,FCB CALL BDOS JMP MFN02 ; ;<> ;<> MFN01: LXI H,MFCUR LXI D,FCB MVI B,12 CALL MOVER MVI C,SRCHF LXI D,FCB CALL BDOS ;<> LXI H,MFREQ LXI D,FCB MVI B,12 CALL MOVER MVI C,SRCHN LXI D,FCB CALL BDOS ;<> ; ;<> MFN02: INR A STC RZ ;<> DCR A ANI 3 ADD A ADD A ADD A ADD A ADD A ADI 81H MOV L,A MVI H,0 PUSH H ;SAVE NAME POINTER LXI D,MFCUR+1 MVI B,11 CALL MOVER ;<> POP H ;RESTORE NAME POINTER LXI D,FCB+1 MVI B,11 CALL MOVER ;<> XRA A STA FCBEXT STA FCBRNO STA MFFLG1 ;TURN OFF 1ST TIME SW ;<> RET ; ;Temporary storage area ; TABCOL: DB 0 ;COLUMN COUNTER PFLAG: DB 0 ;PRINT REQUEST FLAG MFFLG1: DB 1 ;1ST TIME SW MFREQ: DS 12 ;REQUESTED NAME MFCUR: DS 12 ;CURRENT NAME ; DS 64 ;ROOM FOR STACK STACK: DS 2 ;OLD STACK POINTER SAVED HERE ; DSKBUF: DS 16384 ;16K BUFFER ; ;BDOS equates ; OPEN EQU 15 SRCHF EQU 17 SRCHN EQU 18 STDMA EQU 26 BDOS EQU 5 FCB EQU 5CH FCB2 EQU 6CH FCBEXT EQU FCB+12 FCBRNO EQU FCB+32 ; END