home *** CD-ROM | disk | FTP | other *** search
- * PROGRAM NAME: LIST
- * AUTHOR: RICHARD CONN
- * VERSION: 1.0
- * DATE: 10 FEB 81
- * PREVIOUS VERSIONS: -None-
- VERS equ 10 ; Version Number
-
- *
- *
- * Section 0: Introduction to the LIST Program
- *
-
-
-
- *
- * LIST is a CP/M utility which displays a file on the user console in
- * paged mode. It prints 24 lines of text and pauses; typing a ^C at this point
- * returns to CP/M, while any other character continues. If a line is more than
- * LINE$LENGTH character long, it is broken and the line count is incremented
- * accordingly.
- *
-
- *
- * The structure of the LIST Program is as follows --
- *
- * Section Functions/Routines
- * ------- ------------------
- *
- * 0 Introduction and Documentation
- *
- * 1 Initialization of the LIST Program
- * Significant Labels are:
- * OPTION: Command Line option processing
- * OPTION$NUMBER: Set the Line Numbering Flag (/N)
- * DRIVE: Extract the disk drive letter from the command line
- *
- * 2 Mainline of the LIST Program
- * Significant Labels are:
- * LIST: Open files, perform tests, etc
- * LIST1: Start processing loop
- * LIST$LOOP: Main program loop
- *
- * 3 Support Utilties
- * Significant Routines are:
- * PRINT$ID: Print Program ID
- * TYP$COMP: Compare the 3-byte file type pted to by HL to
- * the FCB type; return w/Zero Set if match
- * PRINT$MESSAGE: Print string pted to by return address;
- * string ends in 0
- * LOADER: Copy top of buffer down to front of buffer and
- * load up to 16K into buffer
- * LOADER1: Load the buffer pted to by HL for B blocks (max)
- * CRLF: Print <CR> <LF> (no regs affected)
- * CHAR$OUT: Print char in A; no regs affected
- * CHAR$IN: Input char in A; only PSW affected
- * PRINT$LINE: Print line pted to by HL on console; process
- * line numbering, tab expansion, line overflow fcts
- * PRINT$NUMBER: Print HL as up to 5 decimal digits with
- * leading <SP>; follow by <SP>
- *
- * 4 Buffers
- *
-
- NUMBER$LINES equ 24 ; Number of lines/screen
- LINE$LENGTH equ 77 ; Maximum number of characters/line
- NUMBER$LENGTH equ 7 ; Number of characters in line number
-
- *
- * DEFINE MISCELLANEOUS CONSTANTS USED IN PROGRAM
- *
- OPT$CHAR equ '/' ; Option character
- CR equ 13 ; <CR>
- LF equ 10 ; <LF>
- BS equ 8 ; <BS>
- TAB equ 9 ; <TAB>
- BEL equ 7 ; <BEL>
- CPM equ 0 ; Warm Boot Address
- BUFF equ 80H ; CP/M Buffer
- FCB equ 5CH ; CP/M FCB
- WBADR equ 1 ; CP/M Warm Boot Address
- BDOS equ 5 ; CP/M BDOS Entry Point
- CTRLC equ 'C'-'@' ; ^C
- CTRLZ equ 'Z'-'@' ; ^Z
-
- *
- *
- * Section 1: Initialization of LIST Program
- *
-
-
-
- ORG 100H
-
- LXI H,BUFF ; SCAN FOR OPTION
- MOV A,M ; GET CHAR COUNT
- ADD L ; ADD TO HL
- MOV L,A
- MOV A,H
- ACI 0
- MOV H,A
- INX H ; HL PTS TO CHAR AFTER LAST CHAR IN COMMAND LINE
- MVI M,0 ; STORE ENDING 0
- LXI H,BUFF+1 ; PT TO 1ST CHAR
- PUSH H ; SAVE PTR FOR LATER
- XRA A ; A=0
- STA NFLG ; TURN OFF LINE NUMBERING FLAG
- STA OVFL ; TURN OFF LINE LENGTH OVERFLOW FLAG
- OPTION:
- MOV A,M ; SCAN FOR OPTION
- ORA A ; DONE?
- JZ OPTION$DONE
- INX H ; PT TO NEXT
- CPI OPT$CHAR ; OPTION?
- JNZ OPTION
- MOV A,M ; GET OPTION LETTER
- CPI 'N' ; NUMBER LINES?
- JZ OPTION$NUMBER
- CALL PRINT$ID ; PRINT PROGRAM ID
- CALL PRINT$MESSAGE
- DB CR,LF,' The LIST command takes the following format --'
- DB CR,LF,' LIST d:filename.typ [/N]'
- DB CR,LF,' Only the "/N" option is available; this option prints'
- DB CR,LF,'line numbers in front of each line.'
- DB CR,LF,' The drive specification "d:" is optional.',0
- JMP CPM
- * THIS OPTION TURNS ON THE LINE NUMBERING FLAG
- OPTION$NUMBER:
- MVI A,0FFH ; TURN ON FLAG
- STA NFLG
- JMP OPTION
- * DONE PROCESSING OPTIONS
- OPTION$DONE:
- POP H ; GET PTR TO COMMAND LINE
- DRIVE:
- MOV A,M ; SCAN FOR DRIVE NAME
- ORA A ; DONE?
- JZ LIST
- INX H ; PT TO NEXT CHAR
- CPI ' ' ; NON-SPACE?
- JZ DRIVE ; CONTINUE SCAN IF SO
- MOV A,M ; CHECK FOR COLON
- CPI ':' ; COLON MEANS DRIVE NAME PRECEEDS
- JNZ LIST
- DCX H ; PT TO DRIVE NAME
- MOV A,M ; GET IT
- SUI 'A' ; ADJUST FROM LETTER TO NUMBER (A=0,B=1,ETC)
- JC DRIVE$ERROR
- CPI 16 ; IN RANGE?
- JNC DRIVE$ERROR
- MOV E,A ; PLACE NUMBER IN E
- MVI C,14 ; SELECT DISK
- CALL BDOS
- JMP LIST
- DRIVE$ERROR:
- CALL PRINT$MESSAGE
- DB CR,LF,'ERROR: Invalid Drive Specification',0
- JMP CPM
-
- *
- *
- * Section 2: Mainline of LIST Program
- *
-
-
-
- LIST:
- CALL PRINT$ID ; PRINT PROGRAM ID
- LXI H,COM$TYPE ; DON'T PRINT *.COM OR *.OBJ FILES
- CALL TYP$COMP ; COMPARE TYPES
- JZ TYPE$ERROR
- LXI H,OBJ$TYPE
- CALL TYP$COMP
- JNZ LIST0
- TYPE$ERROR:
- CALL PRINT$MESSAGE
- DB CR,LF,'ERROR: Attempt to List COM or OBJ File',0
- JMP CPM
- LIST0:
- LXI D,FCB ; TRY TO OPEN FILE
- MVI C,15 ; OPEN FILE
- CALL BDOS
- CPI 0FFH ; ERROR?
- JNZ LIST1
- CALL PRINT$MESSAGE
- DB CR,LF,'ERROR: File Not Found',0
- JMP CPM
-
- LIST1:
- CALL CRLF ; NEW LINE
- LXI H,BUFFER ; FILE BUFFER (16K)
- MVI B,8*16 ; LOAD 16K OF FILE (MAX)
- CALL LOADER1 ; LOAD BUFFER PTED TO BY HL FOR 16K
- LXI H,BUFFER ; PT TO FIRST CHARACTER
- LDA NFLG ; NUMBER LINES?
- ORA A ; SET FLAGS
- JZ LIST$LOOP
- PUSH H ; SAVE HL
- LXI H,0 ; SET FOR 1ST LINE NUMBER
- SHLD LINE$NUMBER
- POP H ; RESTORE HL
-
- *
- * MAIN LOOP FOR PRINTING LINES
- *
- LIST$LOOP:
- MVI C,NUMBER$LINES ; NUMBER OF LINES/SCREEN
- LIST$LOOP1:
- CALL PRINT$LINE ; PRINT ONE LINE
- CPI CTRLZ
- JZ CPM
- CPI LF ; LINE FEED?
- JNZ LIST$LOOP2
- INX H ; PT TO CHAR AFTER <LF>
- MOV A,M ; GET POSSIBLE ^Z
- CPI CTRLZ ; ^Z IF SO
- JZ CPM
- LIST$LOOP2:
- DCR C ; COUNT DOWN
- JNZ LIST$LOOP3
- CALL CHAR$IN ; WAIT FOR CHAR
- CALL CRLF ; NEW LINE
- CPI CTRLC ; ^C?
- JZ CPM ; ABORT IF SO
- JMP LIST$LOOP ; CONTINUE
- LIST$LOOP3:
- CALL CRLF ; NEW LINE
- JMP LIST$LOOP1
-
- *
- *
- * Section 3: Support Utilities
- *
-
-
-
- *
- * THIS ROUTINE PRINTS THE PROGRAM ID
- *
- PRINT$ID:
- CALL PRINT$MESSAGE
- DB 'LIST Version ',VERS/10+'0','.',(VERS MOD 10)+'0',0
- RET
-
- *
- * THIS ROUTINE COMPARES THE THREE BYTES PTED TO BY HL AGAINST THE TYPE
- * IN THE FCB; RETURNS W/ZERO SET IF MATCH
- *
- TYP$COMP:
- LXI D,FCB+9 ; PT TO TYPE IN FCB
- MVI B,3 ; 3 BYTES
- TYP$COMP$LOOP:
- LDAX D ; GET BYTE
- CMP M ; COMPARE
- RNZ
- INX H ; PT TO NEXT
- INX D
- DCR B
- JNZ TYP$COMP$LOOP
- RET
-
- *
- * PRINT MESSAGE PTED TO BY RETURN ADDRESS ENDING IN 0
- *
- PRINT$MESSAGE:
- XTHL ; SAVE HL AND GET PTR
- PRINT$MESSAGE$LOOP:
- MOV A,M ; GET CHAR
- INX H ; PT TO NEXT
- ORA A ; DONE?
- JZ PRINT$MESSAGE$DONE
- CALL CHAR$OUT ; PRINT IT
- JMP PRINT$MESSAGE$LOOP
- PRINT$MESSAGE$DONE:
- XTHL ; RESTORE HL AND RETURN ADDRESS
- RET
-
- *
- * THIS ROUTINE LOADS THE FILE BUFFER
- * ENTRY POINT 'LOADER' COPIES THE END OF THE FILE BUFFER DOWN TO THE
- * BEGINNING AND LOADS THE REST OF THE BUFFER (UP TO 16K).
- * ENTRY POINT 'LOADER1' LOADS THE BUFFER POINTED TO BY HL FOR B-BLOCKS
- * (1 BLOCK = 128 BYTES).
- *
- LOADER:
- PUSH B ; SAVE BC
- LXI H,BUFFER$LAST ; PT TO LAST BLOCK
- LXI D,BUFFER ; PT TO 1ST BLOCK
- CALL MOVE$BLOCK ; MOVE BLOCK FROM HL TO DE
- CALL MOVE$BLOCK ; MOVE PAGE (2 BLOCKS)
- XCHG ; PT TO 2ND BLOCK
- MVI B,8*16-2 ; 2 BLOCKS LESS THAN 16K
- CALL LOADER1 ; LOAD BLOCKS
- POP B ; RESTORE BC
- RET
- LOADER1:
- CALL LOADER2 ; LOAD NEXT BLOCK
- RNZ ; DONE IF PAST EOF
- LXI D,BUFF ; PT TO BUFFER
- XCHG ; EXCHANGE PTRS
- CALL MOVE$BLOCK ; MOVE BLOCK LOADED INTO FILE BUFFER
- XCHG ; RESTORE PTRS
- DCR B ; COUNT DOWN
- JNZ LOADER1
- RET
- *
- * LOAD BUFFER FROM DISK
- *
- LOADER2:
- PUSH H ! PUSH D ! PUSH B
- LXI D,FCB ; PT TO FILE NAME
- MVI C,20 ; READ BLOCK
- CALL BDOS
- ORA A ; SET FLAG
- POP B ! POP D ! POP H
- RET
-
- *
- * MOVE BLOCK (128 BYTES) FROM HL TO DE
- *
- MOVE$BLOCK:
- PUSH B ; SAVE BC
- MVI B,128 ; 128 BYTES
- MOVE$BLOCK$LOOP:
- MOV A,M ; GET BYTE
- STAX D ; PUT BYTE
- INX H ; PT TO NEXT
- INX D
- DCR B ; COUNT DOWN
- JNZ MOVE$BLOCK$LOOP
- POP B ; RESTORE BC
- RET
-
- *
- * OUTPUT <CR> <LF>; DON'T CHANGE A
- *
- CRLF:
- PUSH PSW ; SAVE A
- MVI A,CR ; <CR>
- CALL CHAR$OUT
- MVI A,LF ; <LF>
- CALL CHAR$OUT
- POP PSW ; GET A
- RET
-
- *
- * CHARACTER OUTPUT ROUTINE
- * OUTPUT CHARACTER IN REG A TO CONSOLE
- *
- CHAR$OUT:
- PUSH H ! PUSH D ! PUSH B ! PUSH PSW
- MOV E,A ; CHAR IN E
- MVI C,2 ; OUTPUT TO CON:
- CALL BDOS
- POP PSW ! POP B ! POP D ! POP H
- RET
-
- *
- * CHARACTER INPUT ROUTINE
- * CHARACTER IS RETURNED IN REG A
- *
- CHAR$IN:
- PUSH H ! PUSH D ! PUSH B
- LXI H,CHAR$IN$RET ; PLACE RETURN ADDRESS ON STACK
- PUSH H
- LHLD WBADR ; INDEX INTO BIOS FOR NO ECHO
- MOV A,L ; ADD 6 FOR CONSOLE INPUT ROUTINE
- ADI 6
- MOV L,A
- MOV A,H
- ACI 0
- MOV H,A ; HL PTS TO ROUTINE
- PCHL ; "CALL" CONSOLE INPUT ROUTINE
- CHAR$IN$RET:
- POP B ! POP D ! POP H
- RET
-
- *
- * PRINT LINE PTED TO BY HL ON CONSOLE
- *
- PRINT$LINE:
- PUSH B ; SAVE LINE COUNT
- MVI C,0 ; SET CHAR COUNT
- LDA NFLG ; NUMBER LINE?
- ORA A ; 0=NO
- JZ PRINT$LINE1
- LDA OVFL ; OVERFLOW FROM PREVIOUS LINE?
- ORA A ; 0=NO
- JNZ PRINT$LINE1
- PUSH H ; SAVE PTR TO LINE
- LHLD LINE$NUMBER ; FETCH AND INCREMENT LINE NUMBER
- INX H
- SHLD LINE$NUMBER
- CALL PRINT$NUMBER ; PRINT LINE NUMBER
- POP H ; RESTORE PTR TO LINE
- PRINT$LINE1:
- XRA A ; TURN OFF OVERFLOW FLAG
- STA OVFL
- LXI D,BUFFER$LAST ; IN LAST BLOCK?
- MOV A,H ; CHECK AGAINST H
- CMP D
- JNZ PRINT$LINE$LOOP
- PUSH H ; SAVE PTR TO LINE (RELATIVE OFFSET IN L)
- CALL LOADER ; LOAD NEXT 16K
- LXI H,BUFFER ; PT TO 1ST BYTE OF BLOCK
- POP D ; GET RELATIVE OFFSET IN E
- MOV L,E ; RELATIVE OFFSET IN L -- CONTINUE
- PRINT$LINE$LOOP:
- MOV A,M ; GET CHAR FROM FILE
- INX H ; PT TO NEXT CHAR
- ANI 7FH ; MASK OUT MSB
- CPI CTRLZ ; PROCESS EOF
- JZ PRINT$LINE$CR
- CPI BS ; PROCESS <BS>
- JZ PRINT$LINE$BS
- CPI TAB ; PRINT <TAB>
- JZ PRINT$LINE$TAB
- CPI CR ; PROCESS EOL
- JZ PRINT$LINE$CR
- CPI ' ' ; DON'T OUTPUT LESS THAN <SP>
- JC PRINT$LINE$LOOP
- CPI 7EH ; DON'T OUTPUT IF GREATER THAN OR EQUAL TO 7EH
- JNC PRINT$LINE$LOOP
- CALL CHAR$OUT ; PRINT CHAR
- INR C ; INCREMENT CHAR COUNT
- CALL OVFL$TEST ; CHECK FOR LINE OVERFLOW
- JMP PRINT$LINE$LOOP
- PRINT$LINE$BS:
- MOV A,C ; POSSIBLE TO <BS>?
- ORA A ; 0=NO
- JZ PRINT$LINE$LOOP
- MVI A,BS ; PRINT <BS>
- CALL CHAR$OUT
- DCR C ; COUNT DOWN
- JMP PRINT$LINE$LOOP
- PRINT$LINE$TAB:
- MVI A,' ' ; PRINT <SP>
- CALL CHAR$OUT
- INR C ; INCREMENT COUNT
- CALL OVFL$TEST ; CHECK FOR LINE OVERFLOW
- MOV A,C ; MULTIPLE OF 8?
- ANI 7 ; MASK FOR 3 LSB
- JNZ PRINT$LINE$TAB
- JMP PRINT$LINE$LOOP
- PRINT$LINE$CR:
- MOV A,M ; GET POSSIBLE <LF>
- POP B ; RESTORE LINE COUNT
- RET
-
- *
- * TEST FOR LINE OVERFLOW AND PRINT OVERFLOW CHARS IF SO
- *
- OVFL$TEST:
- LDA NFLG ; NUMBERING LINES?
- ORA A ; 0=NO
- JZ OVFL$TEST1
- LDA OVFL ; IN OVERFLOW?
- ORA A ; 0=NO
- JNZ OVFL$TEST1
- * WE ARE ON A NUMBERED LINE
- MVI A,LINE$LENGTH ; GET LINE LENGTH
- SUI NUMBER$LENGTH ; SUBTRACT LENGTH OF LEADING NUMBER
- JMP OVFL$TEST2
- * WE ARE NOT ON A NUMBERED LINE
- OVFL$TEST1:
- MVI A,LINE$LENGTH ; CHECK CHAR COUNT
- OVFL$TEST2:
- CMP C ; OK?
- RNZ
- * CHECK TO SEE IF ONE OF NEXT 3 CHARS IS A <CR>
- MOV A,M ; NEXT CHAR A <CR>?
- ANI 7FH ; MASK OUT MSB
- CPI CR
- RZ
- INX H ; NEXT CHAR A <CR>?
- MOV A,M
- ANI 7FH
- DCX H
- CPI CR
- RZ
- INX H ; 3RD CHAR A <CR>?
- INX H
- MOV A,M
- ANI 7FH
- DCX H
- DCX H
- CPI CR
- RZ
- * NONE OF THEM ARE, SO OVERFLOW
- MVI A,0FFH ; SET OVERFLOW FLAG
- STA OVFL
- MVI A,' ' ; PRINT OVERFLOW CHARS
- CALL CHAR$OUT
- MVI A,'<'
- CALL CHAR$OUT
- POP D ; CLEAR STACK
- MVI A,LF ; FAKE A <LF>
- DCX H ; BACK UP IN PREPARATION FOR <LF> ADVANCE
- POP B ; RESTORE LINE COUNT
- RET ; RETURN TO MAIN LOOP
-
- *
- * PRINT NUMBER IN HL AS UP TO 5 DECIMAL DIGITS FOLLOWED BY A <SP>
- * AFFECT NO REGISTERS
- *
- PRINT$NUMBER:
- PUSH H ! PUSH D ! PUSH B ! PUSH PSW
- MVI A,0FFH
- STA LDSP ; TURN OFF LEADING <SP> FLAG
- LXI D,10000 ; DETERMINE 10,000'S COUNT
- CALL PNUM
- LXI D,1000 ; DETERMINE 1,000'S COUNT
- CALL PNUM
- LXI D,100 ; 100'S
- CALL PNUM
- LXI D,10 ; 10'S
- CALL PNUM
- MOV A,L ; 1'S
- ADI '0' ; CONVERT TO ASCII
- CALL CHAR$OUT ; PRINT IT
- MVI A,':' ; PRINT COLON
- CALL CHAR$OUT
- MVI A,' ' ; PRINT <SP>
- CALL CHAR$OUT
- POP PSW ! POP B ! POP D ! POP H
- RET
- *
- * PNUM IS A UTILITY TO SUBTRACT DE FROM HL UNTIL HL<0; PRINT NUMBER OF TIMES
- * SUBTRACTION WAS DONE; IF ZERO AND LEADING SPACE FLAG SET, PRINT <SP>;
- * ELSE, PRINT DIGIT AND CLEAR LEADING SPACE FLAG
- * ON EXIT, HL=HL-DE
- *
- PNUM:
- MVI C,'0' ; SET DIGIT
- PNUM1:
- MOV A,L ; GET NUMBER
- SUB E
- MOV L,A
- MOV A,H
- SBB D
- MOV H,A ; HL=HL-DE
- JC PNUM2
- INR C ; INCREMENT COUNT
- JMP PNUM1
- PNUM2:
- MOV A,L ; ADD BACK IN SO HL IS AGAIN 0 OR POS
- ADD E
- MOV L,A
- MOV A,H
- ADC D
- MOV H,A ; HL RESTORED
- MOV A,C ; GET DIGIT
- CPI '0' ; ZERO?
- JNZ PNUM3
- LDA LDSP ; LEADING <SP>?
- ORA A ; 0=NO
- JZ PNUM3
- MVI A,' ' ; PRINT <SP>
- JMP PNUM4
- PNUM3:
- XRA A ; NO LEADING <SP>
- STA LDSP ; TURN OFF FLAG
- MOV A,C ; GET CHAR
- PNUM4:
- CALL CHAR$OUT
- RET
-
- *
- *
- * Section 4: Buffers
- *
-
- COM$TYPE:
- DB 'COM' ; FOR COMPARISON AGAINST COM FILE TYPE
- OBJ$TYPE:
- DB 'OBJ' ; FOR COMPARISON AGAINST OBJ FILE TYPE
- LDSP:
- DS 1 ; LEADING <SP> FLAG (0=NO)
- OVFL:
- DS 1 ; LINE LENGTH OVERFLOW FLAG (0=NO)
- NFLG:
- DS 1 ; LINE NUMBER FLAG (0=NO)
- LINE$NUMBER:
- DS 2 ; LINE NUMBER STORAGE BUFFER
-
-
- DS 60 ; STACK SPACE
- STACK EQU $
-
- ORG $/256*256+256
- BUFFER:
- DS 128*(16*8-2) ; FILE BUFFER SPACE
- BUFFER$LAST:
- DS 128*2 ; LAST BLOCK
-
- END