home *** CD-ROM | disk | FTP | other *** search
- ; THIS PROGRAM PRINTS THE LAST FEW LINES OF A TEXT FILE.
- ;
- ; USAGE: TAIL -n filename
- ; -n is optional, limits output to n lines (20 default)
- ;
- ; BY JON DART, DEPT. OF ANTHROPOLOGY, UCSD C-001, LA JOLLA, CA 92093
- ;
- ; VERSION 1.1: 15-MAR-85
- ; VERSION 1.0: 15-JAN-85
- ;
- BUFSIZ EQU 64 ;SIZE OF BUFFER IN RECORDS
-
- ; CP/M SYSTEM DEFINITIONS:
-
- BOOT EQU 0
- BDOS EQU 0005H
- DEFFCB EQU 005CH
- DEFBUF EQU 0080H
- FCBSIZ EQU 36
- SECSIZ EQU 128
- R0 EQU 33
- R2 EQU 35
-
- CONOUT EQU 2
- PRTSTR EQU 09H
- VERS EQU 0CH
- FOPEN EQU 0FH
- FCLOSE EQU 10H
- SETDMA EQU 1AH
- RDRAND EQU 21H
- CFS EQU 23H
-
- ; ASCII CHARACTERS:
-
- LF EQU 0AH
- CR EQU 0DH
- TAB EQU 09H
- SPACE EQU 20H
- CTRL$Z EQU 26
-
- ORG 100H
-
- TAIL EQU $
- LXI H,0
- DAD SP
- SHLD OLDSTK ;SAVE OLD STACK POINTER
- LXI SP,STACK
- CALL CRLF
- MVI C,VERS
- CALL BDOS
- MOV A,L
- CPI 20H
- JNC VERSOK ;IF NOT CP/M 2.2
- LXI D,MSG0
- MVI C,PRTSTR
- CALL BDOS
- JMP EXIT2
- VERSOK: LXI H,FCB
- MVI B,FCBSIZ
- CALL ZERO ;ZERO FCB
- LXI H,DEFBUF ;GET BYTE COUNT FOR COMMAND LINE
- MOV A,M
- ANA A
- JZ NONAME ;IF NO NAME
- PUSH H
- MOV E,M
- MVI D,0
- DAD D
- INX H
- MVI M,0 ;PUT 0 BYTE AT END OF COMMAND LINE
- POP H
- INX H
- CALL SKIPS ;SKIP SPACES
- JC NONAME ;IF END OF LINE
- CPI '-'
- JNZ NONUM ;IF NO NUMBER SPECIFIED
- INX H
- MVI C,0
- PUSH H
- CD: MOV A,M ;HAVE NUMBER, COUNT NUMBER OF DIGITS
- CPI '0'
- JC NODGT
- CPI '9'+1
- JNC NODGT
- INX H
- INR C
- JMP CD
- NODGT: SHLD NUMEND ;SAVE ADDRESS AFTER NUMBER
- POP H
- CALL DTOBIN ;CONVERT NUMBER TO BINARY
- JC NONAME ;IF ERROR
- XCHG
- INX H
- SHLD NUMLIN ;STORE AS # LINES
- LHLD NUMEND ;POINT TO 1 PAST NUMBER
- CALL SKIPS
- JC NONAME
- NONUM: LXI D,FCB
- CALL PACK ;MOVE NAME INTO FCB
- JMP NAMEOK
- NONAME: LXI D,MSG1
- MVI C,PRTSTR
- CALL BDOS
- JMP EXIT2
- NAMEOK:
- LXI D,FCB
- MVI C,FOPEN
- PUSH D
- CALL BDOS ;TRY TO OPEN FILE
- POP D
- CPI 0FFH
- JNZ OPENOK ;IF OK
- BADOPN: XCHG
- LXI D,FILNAM
- CALL FCOPY ;COPY FILE NAME INTO MESSAGE
- LXI D,MSG2
- MVI C,PRTSTR
- CALL BDOS ;PRINT MESSAGE
- JMP EXIT
-
- SKIPS1: INX H
- SKIPS: MOV A,M
- ANA A
- STC
- RZ
- CPI SPACE
- JZ SKIPS1
- CPI TAB
- JZ SKIPS1
- ANA A
- RET
-
- ; COPY FILE NAME FROM COMMAND LINE TO FCB
- ; ENTRY: (HL) POINTS TO FILE NAME
- ; (DE) POINTS TO FCB
- ;
- PACK: INX H
- MOV A,M
- CPI ':'
- DCX H
- JZ HAVED ;IF DRIVE SPECIFIED
- XRA A
- STAX D ;ELSE PUT 0 IN 1ST BYTE
- JMP PACK2
- HAVED: MOV A,M
- SUI 'A'-1
- STAX D
- INX H
- INX H
- PACK2: INX D
- PUSH H
- PUSH D
- XCHG
- MVI B,11
- MVI A,SPACE
- CALL FILL ;FILL NAME FIELD WITH SPACES
- POP D
- POP H
- MVI C,8
- PACK3: MOV A,M ;COPY NAME
- ANA A
- RZ
- CPI SPACE
- RZ
- INX H
- CPI '.'
- JZ PACK4
- STAX D
- INX D
- DCR C
- JNZ PACK3
- MOV A,M ;15-MAR-85
- ANA A ;15-MAR-85
- RZ ;15-MAR-85
- INX H ;FIXES BUG ;15-MAR-85
- JMP PACK5
- PACK4: XCHG
- MOV B,C
- MVI A,SPACE
- CALL FILL
- XCHG
- PACK5: MVI C,3 ;COPY EXTENSION
- PACK6: MOV A,M
- ANA A
- RZ
- CPI SPACE
- RZ
- STAX D
- INX H
- INX D
- DCR C
- JNZ PACK6
- RET
-
- ZERO: XRA A
- FILL: MOV M,A
- INX H
- DCR B
- JNZ FILL
- RET
-
- OPENOK EQU $
- LXI D,FCB
- MVI C,CFS
- CALL BDOS ;COMPUTE FILE SIZE
- LHLD FCB+R0 ;GET SIZE
- MOV A,L
- ORA H
- JZ EXIT ;IF 0
- SHLD FILSIZ ;SAVE SIZE
- LXI D,BUFSIZ
- CALL SUBHLDE ;SUBTRACT BUFFER SIZE
- JC SMALL ;IF FILE SIZE < BUFFER SIZE
- PUSH H
- LXI H,BUFSIZ ;SET BUFFER SIZE
- SHLD NREAD ;AS NUMBER OF RECORDS TO READ
- POP H
- JMP GOTSIZ
- SMALL: LHLD FILSIZ ;SET FILE SIZE
- SHLD NREAD ;AS NUMBER OF RECORDS TO READ
- LXI H,0 ;START FROM RECORD 0
- GOTSIZ: SHLD FCB+R0 ;SET RANDOM RECORD BYTES
- CALL FILBUF ;FILL BUFFER FROM DISK
- LHLD NREAD
- DCX H
- PUSH H
- POP B
- LXI D,SECSIZ
- LXI H,BUFFER
- MLOOP: MOV A,B ;COMPUTE ADDRESS OF START OF LAST SECTOR
- ORA C
- JZ MDONE
- DAD D
- DCX B
- JMP MLOOP
- MDONE: MVI C,SECSIZ
- FCZ: MOV A,M ;SEARCH FOR ^Z
- CPI CTRL$Z
- JZ FOUND
- INX H
- DCR C
- JNZ FCZ
- FOUND: SHLD ENDTXT ;SAVE END OF TEXT ADDRESS
- LXI D,BUFFER
- DCX H ;POINT TO CHAR. BEFORE ^Z
- PUSH H
- LHLD NUMLIN
- PUSH H
- POP B ;LINE COUNT IN (BC)
- POP H
- SRC: CALL COMPRP
- JZ BEGIN ;IF REACHED START OF BUFFER
- MOV A,M ;GET BYTE
- DCX H
- CPI LF
- JZ GOTLF ;IF LF
- CPI CR
- JNZ SRC ;IF NOT CR
- GOTCR: DCX B ;FOUND CR, COUNT A LINE
- MOV A,M ;GET PREVIOUS CHAR.
- CPI LF ;IF LF,
- JNZ NOSKIP
- DCX H ;SKIP IT
- NOSKIP: MOV A,B ;GET LINE COUNT
- ORA C ;MORE TO GO?
- JNZ SRC ;YES, LOOP
- INX H ;START OF RIGHT LINE FOUND
- JMP BEGIN ;GO PRINT
- GOTLF: DCX B ;COME HERE IF FOUND LF
- MOV A,M ;IF PREVIOUS CHAR. = CR
- CPI CR
- JNZ NOSKIP
- DCX H ;SKIP IT
- JMP NOSKIP
- BEGIN: PUSH H
- LHLD ENDTXT
- XCHG ;PUT END OF BUFFER ADDR. IN (DE)
- POP H
- SHOW: CALL COMPRP ;DISPLAY TEXT
- JZ EXIT ;UNTIL END OF BUFFER
- MOV A,M
- CALL COUT
- INX H
- JMP SHOW
-
- ; FILBUF - FILL BUFFER FROM FILE
- ;
- ; ENTRY: NONE
- ;
- ; EXIT: 'C'=1 IF ERROR
- ;
- FILBUF EQU $
- LXI D,BUFFER ;BUFFER ADDRESS IN (DE)
- LHLD NREAD
- PUSH H
- POP B ;(BC) = COUNT OF SECTORS TO READ
- READ11: PUSH D
- PUSH B
- MVI C,SETDMA
- CALL BDOS ;SET DMA ADDRESS
- LXI D,FCB
- MVI C,RDRAND
- CALL BDOS ;READ A SECTOR
- ANA A
- POP B
- POP D
- JNZ READ12 ;QUIT IF END OF FILE
-
- DCX B ;COUNT # SECTORS READ
- XCHG
- LXI D,SECSIZ
- DAD D ;UPDATE BUFFER ADDRESS
- XCHG
- LHLD FCB+R0
- INX H ;ADVANCE FCB
- SHLD FCB+R0 ;TO NEXT SECTOR
- MOV A,C ;GET # SECTORS TO READ
- ORA B
- JNZ READ11 ;LOOP TILL DONE
-
- READ12: ANA A ;CLEAR CARRY
- RET
-
- EXIT: LXI D,FCB ;CLOSE FILE
- MVI C,FCLOSE
- CALL BDOS
- EXIT2: LHLD OLDSTK
- SPHL
- RET ;RETURN TO CCP
-
- FCOPY: MOV A,M
- INX H
- ANA A
- JZ NODRV
- ADI 'A'-1
- STAX D
- INX D
- MVI A,':'
- STAX D
- INX D
- NODRV: MVI B,11
- FCOPY1: MOV A,M
- CPI SPACE
- JZ NOCOPY
- STAX D
- INX D
- NOCOPY: INX H
- DCR B
- RZ
- MOV A,B
- CPI 3
- JNZ FCOPY1
- MVI A,'.'
- STAX D
- INX D
- JMP FCOPY1
-
- ; UTILITY SUBROUTINES:
-
- ; DTOBIN - CONVERT A 5-DIGIT (MAX.) UNSIGNED DECIMAL NUMBER INTO A
- ; BINARY VALUE.
- ;
- ; ENTRY: (C) = NO. OF DIGITS
- ; (HL) POINTS TO CHAR. STRING (MSD FIRST)
- ;
- ; EXIT: (DE) = CONVERTED NUMBER
- ; 'C' FLAG SET IF OVERFLOW (>64384) OR ERROR
- ;
- ; USES: ALL 8080 REGS.
- ;
- DGTPTR: DS 2
- DTOBIN: XRA A
- MOV D,A
- MOV E,A ;CLEAR (DE) - SERVES AS ACCUMULATOR
- CMP C ;MAKE SURE (C) NOT ZERO
- RZ
- PUSH H
- DTOB: SHLD DGTPTR ;SAVE (HL) AS DIGIT POINTER
- MOV A,M ;GET DIGIT
- POP H
- CALL VALDGT ;CHECK FOR VALID DECIMAL DIGIT
- RC ;RETURN WITH ERROR IF NOT
- ANI 0FH ;CONVERT ASCII DIGIT TO BINARY
- XCHG ;SAVE SUM IN (HL)
- MOV E,A ;MOVE DIGIT TO (DE)
- MVI D,0
- MOV B,C
- DCR B ;PUT COUNT IN (B) = DIGIT COUNT -1
- JZ DTOB$1 ;IF =0, SKIP X10 ROUTINE
- DEX10: PUSH H
- CALL MU10 ;MULTIPLY (DE) BY 10
- XCHG
- POP H
- RC ;(B) TIMES - RETURN ON OVERFLOW
- DCR B
- JNZ DEX10
- DTOB$1: DAD D ;ADD PRODUCT TO RESULT
- RC ;RETURN ON OVERFLOW
- XCHG ;SAVE NEW SUM
- DCR C
- RZ ;FINISHED IF COUNT=0
- PUSH H
- LHLD DGTPTR
- INX H ;ELSE BUMP DIGIT POINTER
- JMP DTOB ;& CONVERT NEXT DIGIT
- MU10: XCHG
- DAD H
- RC
- MOV D,H
- MOV E,L
- DAD H
- RC
- DAD H
- RC
- DAD D
- RET
-
- ; SUBROUTINE - RETURNS WITH 'C' FLAG SET IF CHAR. IN (A) IS NOT
- ; IN THE RANGE 0-9
-
- VALDGT: CPI '0'
- RC
- CPI ':'
- CMC
- RET
-
- ; CHARACTER OUTPUT
-
- COUT: DS 0
- PUSH H
- PUSH D
- PUSH B
- PUSH PSW
- ANI 07FH
- MOV E,A
- MVI C,CONOUT
- CNZ BDOS
- POP PSW
- POP B
- POP D
- POP H
- RET
-
- ; WRITE CR + LF
-
- CRLF: MVI A,CR
- CALL COUT
- MVI A,LF
- JMP COUT
-
- ; COMPRP = COMPARE REGISTER PAIR
- ;
- ; ENTRY: (HL), (DE) SET
- ;
- ; EXIT: 'Z'=1 IF (HL)=(DE)
- ; 'C'=1 IF (HL)>(DE)
- ;
- COMPRP: MOV A,D
- CMP H
- RNZ
- MOV A,E
- CMP L
- RET
-
- ; SUBHLDE = SUBTRACT (DE) FROM (HL)
- ;
- ; ENTRY: (HL), (DE) SET
- ;
- ; EXIT: (HL) = (HL) - (DE)
- ; 'C' AND 'Z' FLAGS REFLECT RESULTS OF SUBTRACTION
- ;
- ; USES: F,H,L ONLY
- ;
- SUBHLDE: DS 0
- PUSH B
- MOV B,A ;SAVE (A)
- XCHG
- CALL COMPRP ;SET FLAGS
- XCHG
- MOV A,B ;RESTORE (A)
- POP B
- PUSH PSW ;SAVE (A) AND FLAGS
- MOV A,L
- SUB E
- MOV L,A ;DO SUBTRACTION
- MOV A,H
- SBB D
- MOV H,A
- POP PSW ;RESTORE (A) AND FLAGS
- RET
-
- ; MEMORY DEFINITIONS:
- ;
- FCB: DS FCBSIZ
- OLDSTK: DS 2 ;STACK POINTER ON ENTRY
- ENDTXT: DS 2 ;END OF TEXT IN BUFFER
- FILSIZ: DS 2 ;FILE SIZE IN RECORDS
- NREAD: DS 2 ;NUMBER OF RECORDS TO READ FROM FILE
- NUMEND: DS 2 ;END OF NUMBER
- DS 40 ;STACK AREA
- STACK: DS 0 ;TOP OF STACK
- NUMLIN: DW 20 ;NUMBER OF LINES TO LIST
- MSG0: DB CR,LF,'CP/M 2.X REQUIRED.',CR,LF,'$'
- MSG1: DB 'TAIL V. 1.1 BY JON DART'
- DB CR,LF,CR,LF
- DB 'USAGE: TAIL -n filename',CR,LF
- DB SPACE,SPACE,SPACE,SPACE,SPACE,SPACE,SPACE
- DB '-n is optional, shows last n lines of file (default 20)','$'
- MSG2: DB CR,LF,'CAN''T OPEN: '
- FILNAM: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CR,LF,'$'
-
- ENDDATA EQU $
- BUFFER EQU ENDDATA+10;
- END
-