home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
PROGRAMS
/
SORT
/
SORTV-15.LBR
/
SORTV-15.ZQ0
/
SORTV-15.Z80
Wrap
Text File
|
2000-06-30
|
14KB
|
822 lines
; SORTV.ASM ver 1.5
; by Ward Christensen
; (revised 1/26/86)
;
;Simple sort program for sorting lists of names,
;or any other variable length file, with CR/LF
;delimited records.
;
;This is a "simple" program: FILE MUST FIT IN MEMORY.
;
;01/26/86 Changed to z80 code and added ? wildcard skip character
; for fixed column number sort. D. L. Anderton
;
;06/29/81 Cleaned up file and re-tabified it. (KBP)
;
;06/22/81 Changed so MAC is not needed. Changed so alternate or
; standard CP/M may be selected. By Ted Shapin.
;
;01/03/81 Change stack init. By Keith Petersen, W8SDZ
;
;11/15/80 Add @ command (WLC)
;
;10/24/80 Originally written by Ward Christensen
;
;FORMAT:
; SORTV input-name output-name
; OR SORTV name
;
;If the second format is used, the file is read into
;memory, sorted, erased, created, and written back.
;
; The sort will be based on the first characters
; in the file, unless the command is followed by
; an "@" sign, then a string (1 or more characters)
; to skip. If these are present, the line will be
; sorted starting after one of these characters.
;
;Example: SORTV NAMES.SUB @.
;
;Will sort NAMES.SUB by filetype, since it skips past
;the "." before doing the compare.
;
EOF EQU 1AH
CR EQU 0DH
LF EQU 0AH
;
BIAS EQU 0 ;0 FOR STANDARD CP/M, 4200H FOR ALTERNATE CP/M
;
;BDOS/CBIOS EQUATES (VERSION 10)
;
RDCON EQU 1
WRCON EQU 2
PRINT EQU 9
RDCONBF EQU 10
CONST EQU 11
OPEN EQU 15
CLOSE EQU 16
SRCHF EQU 17
SRCHN EQU 18
ERASE EQU 19
READ EQU 20
WRITE EQU 21
MAKE EQU 22
REN EQU 23
STDMA EQU 26
BDOS EQU 5+BIAS
FCB EQU 5CH+BIAS
FCB2 EQU 6CH+BIAS
FCBEXT EQU FCB+12
FCBRNO EQU FCB+32
;
ORG 100H+BIAS
;
;INIT LOCAL STACK
;
LD SP,STACK
;
CALL START
DEFB 'SORTV rev 1.5'
DEFB CR,LF,'$'
;
START: POP DE ;GET ID
LD C,PRINT
CALL BDOS ;PRINT ID
;
;START OF PROGRAM EXECUTION
;
CALL SVSKIP ;SAVE SKIP INFO
CALL CKNAMES ;SEE THAT 2 NAMES ARE THERE
CALL OPENIN ;OPEN INPUT FILE
CALL READN ;READ THE NAMES
CALL SORTN ;SORT THE NAMES
CALL WRITEN ;WRITE THE NAMES
CALL ERXIT
DEFB '++DONE++$'
;
;====> SUBROUTINES
; ----------------
;
;====> SAVE "SKIP TO" INFORMATION
;
SVSKIP: LD HL,81H+BIAS
;
SVSKL: LD A,(HL)
OR A
RET Z ;NO 'SKIP TO'
CP '@' ;SKIP DELIMITER?
INC HL
JP NZ,SVSKL
LD DE,SKIPC ;CHARS TO SKIP
;
SVSKL2: LD A,(HL)
LD (DE),A
INC HL
INC DE
OR A
JP NZ,SVSKL2
RET
;
;====> CHECK THAT 2 NAMES WERE SUPPLIED
;
CKNAMES:LD A,(FCB+1)
CP ' '
JP Z,NONAME
LD A,(FCB2+1)
CP ' '
JP Z,SAMENAM
CP '@' ;SKIP PARM?
JP Z,SAMENAM
LD HL,FCB2
LD DE,OUTNAME
LD BC,12
CALL MOVER
RET
;
;OUTPUT NAME = INPUT NAME
;
SAMENAM:LD HL,FCB
LD DE,OUTNAME
LD BC,12
CALL MOVER
RET
;
NONAME: CALL ERXIT
DEFB '++Error - ',CR,LF
DEFB 'Command format requires an '
DEFB 'input name, and an output name.$'
;
;====> OPEN THE INPUT FILE
;
OPENIN: PUSH BC
PUSH DE
PUSH HL
LD C,OPEN
LD DE,FCB
CALL BDOS
POP HL
POP DE
POP BC
INC A
RET NZ ;SUCCESSFUL? RETURN
CALL ERXIT
DEFB '++Input file not found$'
;
;====> READ IN THE NAMES
;
READN: LD HL,SBUFF ;TO FIRST NAME
;
READNL: CALL READL ;READ ONE LINE
RET C ;GOT EOF, RETURN
CALL CHAIN ;CHAIN THINGS TOGETHER
JP READNL
;
;====> READ ONE LINE
;
READL: LD (CURR),HL ;SAVE CURR LINE PTR
XOR A ;GET 0
LD (HL),A ;INIT FORWARD
INC HL ; POINTER
LD (HL),A ; TO
INC HL ; 0
LD DE,SKIPC ;TO CK SKIP CHARS PRESENT
;
READLLP:LD A,(BDOS+2) ;ARE WE
DEC A ; OVER-
CP H ; FLOW-
JP Z,OFLO ; ING?
PUSH DE
PUSH HL
LD HL,EXTFCB
CALL RDBYTE ;READ A BYTE
POP HL
POP DE
CP EOF ;SET CARRY
SCF ; AND RETURN
RET Z ; IF EOF
LD (HL),A ;STORE CHAR
;TEST FOR SKIP CHAR FOUND
LD B,A ;SAVE FOR COMPARE
LD A,(DE)
OR A ;NO MORE SKIP CHARS?
JP Z,READLNS ;NO MORE
;TEST FOR SKIP WILDCARD ?
CP '?'
JP Z,WLDCRD
;OR SKIP CHAR
CP B ;A SKIP CHAR?
JP NZ,READLNS ;NO, KEEP TRYIN.
WLDCRD: INC DE ;TO NEXT SKIP CHAR
;
READLNS:INC HL ;POINT TO NEXT
LD A,B ;GET CHAR
CP CR ;END OF LINE?
JP NZ,READLLP ; NO, LOOP.
PUSH DE
PUSH HL
LD HL,EXTFCB
CALL RDBYTE ;GOBBLE UP LF
POP HL
POP DE
LD A,(DE) ;GET SKIP CHAR END
OR A ;TEST IT AND SET "NO EOF"
RET Z
;ERROR - NO SKIP CHAR
LD HL,(CURR)
INC HL ;SKIP
INC HL ; POINTER
;
ERPLP: LD E,(HL)
PUSH BC
PUSH DE
PUSH HL
LD C,WRCON
CALL BDOS
POP HL
POP DE
POP BC
LD A,(HL)
INC HL
CP CR
JP NZ,ERPLP
CALL ERXIT
DEFB LF,'++NO SKIP CHAR FOUND++$'
;
OFLO: CALL ERXIT
DEFB '++File won''t fit in memory$'
;
;====> CHAIN RECORDS TOGETHER
;
CHAIN: PUSH HL ;SAVE POINTER
LD HL,(CURR) ;GET CURRENT
EX DE,HL ; TO DE
LD HL,(PREV) ;PREV TO HL
LD (HL),E ;MOVE CURR
INC HL ; TO
LD (HL),D ; PREV
EX DE,HL ;THEN MOVE
LD (PREV),HL ; PREV TO CURR
POP HL
RET
;
;====> SORT THE NAMES
;
SORTN: XOR A ;SHOW NO
LD (SWAPS),A ; SWAPS
LD HL,PTR ;POINT PREV
LD (PREV),HL ; TO PTR
LD HL,(PTR) ;POINT TO FIRST
;
;HANDLE WIERD CASE OF ONLY ONE NAME
;
LD A,(HL) ;GET POINTER
INC HL ;POINT TO NEXT
OR (HL) ;OR TOGETHER
DEC HL ;BACK UP
RET Z ;RETURN IF ONLY ONE
;
SORTL: CALL CMPR ;COMPARE ENTRIES
CALL C,SWAP ;SWAP IF WRONG ORDER
CALL NEXT ;POINT TO NEXT
JP NC,SORTL ;LOOP IF MORE
LD A,(SWAPS) ;ANY
OR A ; SWAPS?
JP NZ,SORTN ;YES, LOOP
RET ;NO, RETURN
;
;----> COMPARE TWO NAMES
;
CMPR: PUSH HL ;SAVE POINTER
LD E,(HL) ;GET NEXT
INC HL ; POINTER
LD D,(HL) ; TO DE
INC DE ;ALIGN POINTERS
;
;SKIP IF NECESSARY
;
LD BC,SKIPC
;
TSTSKIP:LD A,(BC)
OR A
JP Z,COMPL ;NO SKIP
INC BC
;
SKIP1: INC HL
CP '?'
JP Z,WLD2
CP (HL)
JP NZ,SKIP1
WLD2: EX DE,HL ;SWAP
;
SKIP2: INC HL
CP '?'
JP Z,WLD3
CP (HL)
JP NZ,SKIP2
WLD3: EX DE,HL ;PUT THINGS BACK
JP TSTSKIP
;
COMPL: INC DE ;TO NEXT
INC HL ;TO NEXT
LD A,(DE) ;GET ONE
CP (HL) ;COMPARE
JP NZ,COMPNE ;NO COMPARE
CP CR ;END?
JP NZ,COMPL ; NO, LOOP
;
COMPH: POP HL ;RESTORE POINTER
RET ;THEY ARE EQUAL
;
;COMPARE NOT EQUAL - SEE IF END OF ELEMENT,
;AND IF SO, CALL THEM EQUAL
;
COMPNE: LD A,(HL)
CP CR
JP Z,COMPH
LD A,(DE)
CP (HL)
JP COMPH ;CARRY SET AS APPROP
;
;----> SWAP ENTRIES
;
;LOGIC: PTR POINTS TO SOME ENTRY, WHICH POINTS
;TO ANOTHER ENTRY. THEY ARE NOT IN ORDER. THUS:
;POINT PTR TO THE SECOND, POINT THE SECOND TO
;THE FIRST, AND POINT THE FIRST TO WHAT THE
;SECOND USED TO POINT TO.
;
SWAP: LD A,1
LD (SWAPS),A ;SHOW WE SWAPPED
;BC=NEXT
LD C,(HL)
INC HL
LD B,(HL)
DEC HL
;CHAIN CURRENT TO NEXT ONES CHAIN
LD A,(BC)
LD (HL),A
INC BC
INC HL
LD A,(BC)
LD (HL),A
DEC BC
DEC HL
;SAVE CURRENT POINTER IN DE
EX DE,HL
;GET POINTER TO PREV
LD HL,(PREV)
;POINT PREV TO NEXT
LD (HL),C
INC HL
LD (HL),B
;STORE CURR IN NEXT
LD A,E
LD (BC),A
INC BC
LD A,D
LD (BC),A
DEC BC
;RESTORE CURRENT POINTER
EX DE,HL
RET ;CURRENT POINTER IN DE
;
;----> GET NEXT ETRY, CARRY IF NOT 2 MORE
;
NEXT: LD (PREV),HL ;SAVE POINTER
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL ;HL= NEXT
LD A,H ;CARRY ON
OR L ; IF HL
SCF ; =
RET Z ; 0
LD A,(HL) ;GET
INC HL ;SEE IF THERE
OR (HL) ; IS
DEC HL ; ANOTHER
RET NZ ;THERE IS ANOTHER
SCF ;SHOW NOT 2 TO SWAP
RET
;
;====> WRITE THE NAMES
;
WRITEN: LD HL,0 ;INIT
LD (EXTFCB+2),HL ; EFCB
XOR A ;INIT
LD (FCBEXT),A ; THE
LD (FCBRNO),A ; FCB
;RESTORE NAME
LD HL,OUTNAME
LD DE,FCB
LD BC,12
CALL MOVER
PUSH BC
PUSH DE
PUSH HL
LD C,ERASE
LD DE,FCB
CALL BDOS
POP HL
POP DE
POP BC
PUSH BC
PUSH DE
PUSH HL
LD C,MAKE
LD DE,FCB
CALL BDOS
POP HL
POP DE
POP BC
INC A ;MAKE OK?
JP Z,BADOUT ; NO, ERROR
LD HL,(PTR) ;GET FIRST
;
WNLP: CALL WRITEL ;WRITE ONE LINE
JP NC,WNLP ;LOOP IF MORE
LD A,EOF ;WRITE EOF CHAR
PUSH HL
LD HL,EXTFCB
CALL WRBYTE
POP HL
LD HL,EXTFCB ;FLUSH
CALL FLUSH ; BUFFERS
PUSH BC
PUSH DE
PUSH HL
LD C,STDMA ;RESET DMA
LD DE,80H+BIAS
CALL BDOS
POP HL
POP DE
POP BC
PUSH BC
PUSH DE
PUSH HL
LD C,CLOSE
LD DE,FCB
CALL BDOS
POP HL
POP DE
POP BC
CALL ERXIT ; AND EXIT
DEFB '++DONE++$'
;
WRITEL: PUSH HL ;SAVE POINTER
INC HL
;
WRLP: INC HL ;TO NEXT CHAR
LD A,(HL) ;GET CHAR
PUSH HL
LD HL,EXTFCB
CALL WRBYTE ;WRITE IT
POP HL
LD A,(HL) ;SEE IF END
CP CR ; OF LINE
JP NZ,WRLP ;NO, LOOP
LD A,LF ;OTHERWISE
PUSH HL
LD HL,EXTFCB
CALL WRBYTE ;WRITE LF
POP HL
POP HL ;GET POINTER
LD E,(HL) ;GET
INC HL ; FORWARD
LD D,(HL) ; POINTER
EX DE,HL ;PUT IT IN HL
LD A,H ;IS POINTER
OR L ; ZERO?
RET NZ ;NO, RETURN
SCF ;CARRY SHOWS END
RET
;
BADOUT: CALL ERXIT
DEFB '++Can''t make output file$'
;
;FOLLOWING FROM 'EQU10.LIB'---->
;
;MOVE, COMPARE SUBROUTINES
;
MOVER: LD A,(HL)
LD (DE),A
INC HL
INC DE
DEC BC
LD A,B
OR C
JP NZ,MOVER
RET
;
; FROM EQU10.LIB: AS OF 07/19/80
;
;RDBYTE, HL POINTS TO EXTENDED FCB:
;
; 2 BYTE BUFFER ADDR
; 2 BYTE "BYTES LEFT" (INIT TO 0)
; 1 BYTE BUFFER SIZE (IN PAGES)
; 2 BYTE FCB ADDRESS
;
RDBYTE: LD E,(HL)
INC HL
LD D,(HL) ;GET BUFFER ADDR
INC HL
LD C,(HL)
INC HL
LD B,(HL) ;BC = BYTES LEFT
LD A,B ;GET COUNT
OR C
JP NZ,RDBNORD ;NO READ
;
INC HL ;TO BUFFER SIZE
LD A,(HL) ;GET COUNT
ADD A,A ;MULTIPLY BY 2
LD B,A ;SECTOR COUNT IN B
INC HL ;TO FCB
PUSH HL ;SAVE FCB POINTER
LD A,(HL) ;GET..
INC HL
LD H,(HL) ;..ADDR..
LD L,A ;..TO HL
;
RDBLP: LD A,1AH ;GET EOF CHAR
LD (DE),A ;SAVE IN CASE EOF
PUSH DE ;SAVE DMA ADDR
PUSH HL ;SAVE FCB ADDR
PUSH BC
PUSH DE
PUSH HL
LD C,STDMA
CALL BDOS ;SET DMA ADDR
POP HL
POP DE
POP BC
POP DE ;GET FCB
PUSH BC
PUSH DE
PUSH HL
LD C,READ
CALL BDOS
POP HL
POP DE
POP BC
OR A
POP HL ;HL=DMA, DE=FCB
JP NZ,RDBRET ;GOT EOF
LD A,L
ADD A,80H ;TO NEXT BUFF
LD L,A
LD A,H
ADC A,0
LD H,A
EX DE,HL ;DMA TO DE, FCB TO HL
DEC B ;MORE SECTORS?
JP NZ,RDBLP ;YES, MORE
;
RDBRET: POP HL ;GET FCB POINTER
DEC HL ;TO LENGTH
LD A,(HL) ;GET LENGTH
DEC HL ;TO COUNT
LD (HL),A ;SET PAGE COUNT
DEC HL ;TO LO COUNT
DEC HL ;TO HI FCB
DEC HL ;TO EFCB START
JP RDBYTE ;LOOP THRU AGAIN
;
RDBNORD:INC HL ;TO LENGTH
LD A,(HL) ;GET LENGTH (PAGES)
EX DE,HL ;BUFF TO HL
ADD A,H
LD H,A ;HL = END OF BUFF
LD A,L
SUB C
LD L,A
LD A,H
SBC A,B
LD H,A ;HL = DATA POINTER
LD A,(HL) ;GET BYTE
EX DE,HL ;EFCB BACK TO HL
CP 1AH ;EOF?
RET Z ;YES, LEAVE POINTERS
DEC BC ;DECR COUNT
DEC HL ;"BYTES LEFT"
LD (HL),B
DEC HL
LD (HL),C ;STORE BACK COUNT
RET
;
;SAMPLE EFCB:
;
;EFCB DW BUFF ;BUFFER ADDR
; DW 0 ;BYTES LEFT (OR TITE)
; DB 20 ;BUFFER SIZE (IN PAGES)
; DW FCB ;FCB ADDRESS
;
;
;WRBYTE, HL POINTS TO EXTENDED FCB:
;
; 2 BYTE BUFFER ADDR
; 2 BYTE "BYTES LEFT" (INIT TO 0)
; 1 BYTE BUFFER SIZE (IN PAGES)
; 2 BYTE FCB ADDRESS
;
WRBYTE: LD E,(HL)
INC HL
LD D,(HL) ;DE=BUF ADDR
INC HL
LD C,(HL)
INC HL
LD B,(HL) ;BC=BYTES IN BUFF
PUSH DE ;SAVE FCB
EX DE,HL
ADD HL,BC ;TO NEXT BYTE
LD (HL),A ;STORE IT
INC BC ;ONE MORE
EX DE,HL
POP DE
;
;SEE IF BUFFER IS FULL
;
INC HL ;GET
LD A,(HL) ; SIZE
CP B ;FULL?
JP NZ,WRBNOWR ;NO WRITE
;
ADD A,A ;MULTIPLY BY 2
LD B,A ;SECTOR COUNT IN B
INC HL ;TO FCB
PUSH HL ;SAVE FCB POINTER
LD A,(HL) ;GET..
INC HL ;..FCB..
LD H,(HL) ;..ADDR..
LD L,A ;..TO HL
;
WRBLP: PUSH DE ;SAVE DMA ADDR
PUSH HL ;SAVE FCB ADDR
PUSH BC
PUSH DE
PUSH HL
LD C,STDMA
CALL BDOS ;SET DMA ADDR
POP HL
POP DE
POP BC
POP DE ;GET FCB
PUSH BC
PUSH DE
PUSH HL
LD C,WRITE
CALL BDOS
POP HL
POP DE
POP BC
OR A
POP HL ;HL=DMA, DE=FCB
JP NZ,WRBERR ;GOT ERR
LD A,L
ADD A,80H ;TO NEXT BUFF
LD L,A
LD A,H
ADC A,0
LD H,A
EX DE,HL ;DMA TO DE, FCB TO HL
DEC B ;MORE SECTORS?
JP NZ,WRBLP ;YES, MORE
;
WRBRET: POP HL ;GET FCB POINTER
DEC HL ;TO LENGTH
DEC HL ;TO COUNT
LD (HL),0 ;SET 0 TO WRITE
DEC HL ;TO LO COUNT
LD (HL),0
PUSH BC
PUSH DE
PUSH HL
LD C,STDMA
LD DE,80H+BIAS
CALL BDOS
POP HL
POP DE
POP BC
RET
;
WRBNOWR:DEC HL ;TO LENGTH
LD (HL),B ;SET NEW LENGTH
DEC HL
LD (HL),C
RET
;
;FLUSH THE EFCB BUFFERS
;
FLUSH: LD E,(HL)
INC HL
LD D,(HL) ;DE=BUF ADDR
INC HL
LD C,(HL)
INC HL
LD B,(HL) ;BC=BYTES IN BUFF
INC HL ;TO COUNT
LD A,B
OR C
RET Z ;NOTHING TO WRITE
LD A,C ;GET LOW COUNT
ADD A,A ;SHIFT HIGH TO CARRY
LD A,B ;GET LOW COUNTAL
RLA ;MULT BY 2, + CARRY
INC A ;FUDGE FOR PARTIAL SECT
LD B,A ;SAVE SECTOR COUNT
INC HL ;TO FCB
LD A,(HL)
INC HL
LD H,(HL)
LD L,A ;HL=FCB
;
FLUSHL: PUSH BC
PUSH DE
PUSH HL
LD C,STDMA
CALL BDOS
POP HL
POP DE
POP BC
EX DE,HL
PUSH BC
PUSH DE
PUSH HL
LD C,WRITE
CALL BDOS
POP HL
POP DE
POP BC
EX DE,HL
OR A
JP NZ,WRBERR
PUSH HL
LD HL,80H
ADD HL,DE
EX DE,HL
POP HL
DEC B
JP NZ,FLUSHL
EX DE,HL
PUSH BC
PUSH DE
PUSH HL
LD C,CLOSE
CALL BDOS
POP HL
POP DE
POP BC
INC A
RET NZ
CALL ERXIT
DEFB '++OUTPUT FILE CLOSE ERROR ++$'
;
WRBERR: CALL ERXIT
DEFB '++OUTPUT FILE WRITE ERROR++$'
;
;EXIT WITH ERROR MESSAGE
;
MSGEXIT EQU $ ;EXIT W/"INFORMATIONAL" MSG
;
ERXIT: POP DE ;GET MSG
LD C,PRINT
CALL BDOS
;
;EXIT, RESTORING STACK AND RETURN
;
EXIT: JP 0+BIAS
;
;====> START OF WORK AREA
;
EXTFCB: DEFW DKBUF
DEFW 0
DEFB 4
DEFW FCB
PREV: DEFW PTR ;POINTER TO PREV POINTER
SKIPC: DEFB 0 ;SKIP CHARS END
DEFS 100 ;VARIABLE SKIP CHARS
;
DEFS 100 ;STACK AREA
STACK EQU $
;
OUTNAME:DEFS 12 ;OUTPUT FILENAME
SWAPS: DEFS 1
CURR: DEFS 2
PTR: DEFS 2 ;POINTER TO FIRST NAME
;
ORG ($+255) AND 0FF00H;TO PAGE
;
DKBUF: DEFS 256*4 ;4 PAGES OF BUFFER
SBUFF: DEFS 0 ;NAMES READ IN HERE
;
END
WRITE
CALL BDOS
POP HL
POP DE
POP BC
EX DE,HL
OR A
JP NZ,WRBERR