home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
programs
/
sort
/
sortv14.asm
< prev
next >
Wrap
Assembly Source File
|
1994-07-13
|
13KB
|
803 lines
; SORTV.ASM ver 1.4
; by Ward Christensen
; (revised 6/29/81)
;
;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.
;
;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
;
LXI SP,STACK
;
CALL START
DB 'SORTV rev 1.3'
DB CR,LF,'$'
;
START POP D ;GET ID
MVI 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
DB '++DONE++$'
;
;====> SUBROUTINES
; ----------------
;
;====> SAVE "SKIP TO" INFORMATION
;
SVSKIP LXI H,81H+BIAS
;
SVSKL MOV A,M
ORA A
RZ ;NO 'SKIP TO'
CPI '@' ;SKIP DELIMITER?
INX H
JNZ SVSKL
LXI D,SKIPC ;CHARS TO SKIP
;
SVSKL2 MOV A,M
STAX D
INX H
INX D
ORA A
JNZ SVSKL2
RET
;
;====> CHECK THAT 2 NAMES WERE SUPPLIED
;
CKNAMES LDA FCB+1
CPI ' '
JZ NONAME
LDA FCB2+1
CPI ' '
JZ SAMENAM
CPI '@' ;SKIP PARM?
JZ SAMENAM
LXI H,FCB2
LXI D,OUTNAME
LXI B,12
CALL MOVER
RET
;
;OUTPUT NAME = INPUT NAME
;
SAMENAM LXI H,FCB
LXI D,OUTNAME
LXI B,12
CALL MOVER
RET
;
NONAME CALL ERXIT
DB '++Error - ',CR,LF
DB 'Command format requires an '
DB 'input name, and an output name.$'
;
;====> OPEN THE INPUT FILE
;
OPENIN PUSH B
PUSH D
PUSH H
MVI C,OPEN
LXI D,FCB
CALL BDOS
POP H
POP D
POP B
INR A
RNZ ;SUCCESSFUL? RETURN
CALL ERXIT
DB '++Input file not found$'
;
;====> READ IN THE NAMES
;
READN LXI H,SBUFF ;TO FIRST NAME
;
READNL CALL READL ;READ ONE LINE
RC ;GOT EOF, RETURN
CALL CHAIN ;CHAIN THINGS TOGETHER
JMP READNL
;
;====> READ ONE LINE
;
READL SHLD CURR ;SAVE CURR LINE PTR
XRA A ;GET 0
MOV M,A ;INIT FORWARD
INX H ; POINTER
MOV M,A ; TO
INX H ; 0
LXI D,SKIPC ;TO CK SKIP CHARS PRESENT
;
READLLP LDA BDOS+2 ;ARE WE
DCR A ; OVER-
CMP H ; FLOW-
JZ OFLO ; ING?
PUSH D
PUSH H
LXI H,EXTFCB
CALL RDBYTE ;READ A BYTE
POP H
POP D
CPI EOF ;SET CARRY
STC ; AND RETURN
RZ ; IF EOF
MOV M,A ;STORE CHAR
;TEST FOR SKIP CHAR FOUND
MOV B,A ;SAVE FOR COMPARE
LDAX D
ORA A ;NO MORE SKIP CHARS?
JZ READLNS ;NO MORE
CMP B ;A SKIP CHAR?
JNZ READLNS ;NO, KEEP TRYIN.
INX D ;TO NEXT SKIP CHAR
;
READLNS INX H ;POINT TO NEXT
MOV A,B ;GET CHAR
CPI CR ;END OF LINE?
JNZ READLLP ; NO, LOOP.
PUSH D
PUSH H
LXI H,EXTFCB
CALL RDBYTE ;GOBBLE UP LF
POP H
POP D
LDAX D ;GET SKIP CHAR END
ORA A ;TEST IT AND SET "NO EOF"
RZ
;ERROR - NO SKIP CHAR
LHLD CURR
INX H ;SKIP
INX H ; POINTER
;
ERPLP MOV E,M
PUSH B
PUSH D
PUSH H
MVI C,WRCON
CALL BDOS
POP H
POP D
POP B
MOV A,M
INX H
CPI CR
JNZ ERPLP
CALL ERXIT
DB LF,'++NO SKIP CHAR FOUND++$'
;
OFLO CALL ERXIT
DB '++File won''t fit in memory$'
;
;====> CHAIN RECORDS TOGETHER
;
CHAIN PUSH H ;SAVE POINTER
LHLD CURR ;GET CURRENT
XCHG ; TO DE
LHLD PREV ;PREV TO HL
MOV M,E ;MOVE CURR
INX H ; TO
MOV M,D ; PREV
XCHG ;THEN MOVE
SHLD PREV ; PREV TO CURR
POP H
RET
;
;====> SORT THE NAMES
;
SORTN XRA A ;SHOW NO
STA SWAPS ; SWAPS
LXI H,PTR ;POINT PREV
SHLD PREV ; TO PTR
LHLD PTR ;POINT TO FIRST
;
;HANDLE WIERD CASE OF ONLY ONE NAME
;
MOV A,M ;GET POINTER
INX H ;POINT TO NEXT
ORA M ;OR TOGETHER
DCX H ;BACK UP
RZ ;RETURN IF ONLY ONE
;
SORTL CALL CMPR ;COMPARE ENTRIES
CC SWAP ;SWAP IF WRONG ORDER
CALL NEXT ;POINT TO NEXT
JNC SORTL ;LOOP IF MORE
LDA SWAPS ;ANY
ORA A ; SWAPS?
JNZ SORTN ;YES, LOOP
RET ;NO, RETURN
;
;----> COMPARE TWO NAMES
;
CMPR PUSH H ;SAVE POINTER
MOV E,M ;GET NEXT
INX H ; POINTER
MOV D,M ; TO DE
INX D ;ALIGN POINTERS
;
;SKIP IF NECESSARY
;
LXI B,SKIPC
;
TSTSKIP LDAX B
ORA A
JZ COMPL ;NO SKIP
INX B
;
SKIP1 INX H
CMP M
JNZ SKIP1
XCHG ;SWAP
;
SKIP2 INX H
CMP M
JNZ SKIP2
XCHG ;PUT THINGS BACK
JMP TSTSKIP
;
COMPL INX D ;TO NEXT
INX H ;TO NEXT
LDAX D ;GET ONE
CMP M ;COMPARE
JNZ COMPNE ;NO COMPARE
CPI CR ;END?
JNZ COMPL ; NO, LOOP
;
COMPH POP H ;RESTORE POINTER
RET ;THEY ARE EQUAL
;
;COMPARE NOT EQUAL - SEE IF END OF ELEMENT,
;AND IF SO, CALL THEM EQUAL
;
COMPNE MOV A,M
CPI CR
JZ COMPH
LDAX D
CMP M
JMP 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 MVI A,1
STA SWAPS ;SHOW WE SWAPPED
;BC=NEXT
MOV C,M
INX H
MOV B,M
DCX H
;CHAIN CURRENT TO NEXT ONES CHAIN
LDAX B
MOV M,A
INX B
INX H
LDAX B
MOV M,A
DCX B
DCX H
;SAVE CURRENT POINTER IN DE
XCHG
;GET POINTER TO PREV
LHLD PREV
;POINT PREV TO NEXT
MOV M,C
INX H
MOV M,B
;STORE CURR IN NEXT
MOV A,E
STAX B
INX B
MOV A,D
STAX B
DCX B
;RESTORE CURRENT POINTER
XCHG
RET ;CURRENT POINTER IN DE
;
;----> GET NEXT ETRY, CARRY IF NOT 2 MORE
;
NEXT SHLD PREV ;SAVE POINTER
MOV E,M
INX H
MOV D,M
XCHG ;HL= NEXT
MOV A,H ;CARRY ON
ORA L ; IF HL
STC ; =
RZ ; 0
MOV A,M ;GET
INX H ;SEE IF THERE
ORA M ; IS
DCX H ; ANOTHER
RNZ ;THERE IS ANOTHER
STC ;SHOW NOT 2 TO SWAP
RET
;
;====> WRITE THE NAMES
;
WRITEN LXI H,0 ;INIT
SHLD EXTFCB+2 ; EFCB
XRA A ;INIT
STA FCBEXT ; THE
STA FCBRNO ; FCB
;RESTORE NAME
LXI H,OUTNAME
LXI D,FCB
LXI B,12
CALL MOVER
PUSH B
PUSH D
PUSH H
MVI C,ERASE
LXI D,FCB
CALL BDOS
POP H
POP D
POP B
PUSH B
PUSH D
PUSH H
MVI C,MAKE
LXI D,FCB
CALL BDOS
POP H
POP D
POP B
INR A ;MAKE OK?
JZ BADOUT ; NO, ERROR
LHLD PTR ;GET FIRST
;
WNLP CALL WRITEL ;WRITE ONE LINE
JNC WNLP ;LOOP IF MORE
MVI A,EOF ;WRITE EOF CHAR
PUSH H
LXI H,EXTFCB
CALL WRBYTE
POP H
LXI H,EXTFCB ;FLUSH
CALL FLUSH ; BUFFERS
PUSH B
PUSH D
PUSH H
MVI C,STDMA ;RESET DMA
LXI D,80H+BIAS
CALL BDOS
POP H
POP D
POP B
PUSH B
PUSH D
PUSH H
MVI C,CLOSE
LXI D,FCB
CALL BDOS
POP H
POP D
POP B
CALL ERXIT ; AND EXIT
DB '++DONE++$'
;
WRITEL PUSH H ;SAVE POINTER
INX H
;
WRLP INX H ;TO NEXT CHAR
MOV A,M ;GET CHAR
PUSH H
LXI H,EXTFCB
CALL WRBYTE ;WRITE IT
POP H
MOV A,M ;SEE IF END
CPI CR ; OF LINE
JNZ WRLP ;NO, LOOP
MVI A,LF ;OTHERWISE
PUSH H
LXI H,EXTFCB
CALL WRBYTE ;WRITE LF
POP H
POP H ;GET POINTER
MOV E,M ;GET
INX H ; FORWARD
MOV D,M ; POINTER
XCHG ;PUT IT IN HL
MOV A,H ;IS POINTER
ORA L ; ZERO?
RNZ ;NO, RETURN
STC ;CARRY SHOWS END
RET
;
BADOUT CALL ERXIT
DB '++Can''t make output file$'
;
;FOLLOWING FROM 'EQU10.LIB'---->
;
;MOVE, COMPARE SUBROUTINES
;
MOVER MOV A,M
STAX D
INX H
INX D
DCX B
MOV A,B
ORA C
JNZ 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 MOV E,M
INX H
MOV D,M ;GET BUFFER ADDR
INX H
MOV C,M
INX H
MOV B,M ;BC = BYTES LEFT
MOV A,B ;GET COUNT
ORA C
JNZ RDBNORD ;NO READ
;
INX H ;TO BUFFER SIZE
MOV A,M ;GET COUNT
ADD A ;MULTIPLY BY 2
MOV B,A ;SECTOR COUNT IN B
INX H ;TO FCB
PUSH H ;SAVE FCB POINTER
MOV A,M ;GET..
INX H
MOV H,M ;..ADDR..
MOV L,A ;..TO HL
;
RDBLP MVI A,1AH ;GET EOF CHAR
STAX D ;SAVE IN CASE EOF
PUSH D ;SAVE DMA ADDR
PUSH H ;SAVE FCB ADDR
PUSH B
PUSH D
PUSH H
MVI C,STDMA
CALL BDOS ;SET DMA ADDR
POP H
POP D
POP B
POP D ;GET FCB
PUSH B
PUSH D
PUSH H
MVI C,READ
CALL BDOS
POP H
POP D
POP B
ORA A
POP H ;HL=DMA, DE=FCB
JNZ RDBRET ;GOT EOF
MOV A,L
ADI 80H ;TO NEXT BUFF
MOV L,A
MOV A,H
ACI 0
MOV H,A
XCHG ;DMA TO DE, FCB TO HL
DCR B ;MORE SECTORS?
JNZ RDBLP ;YES, MORE
;
RDBRET POP H ;GET FCB POINTER
DCX H ;TO LENGTH
MOV A,M ;GET LENGTH
DCX H ;TO COUNT
MOV M,A ;SET PAGE COUNT
DCX H ;TO LO COUNT
DCX H ;TO HI FCB
DCX H ;TO EFCB START
JMP RDBYTE ;LOOP THRU AGAIN
;
RDBNORD INX H ;TO LENGTH
MOV A,M ;GET LENGTH (PAGES)
XCHG ;BUFF TO HL
ADD H
MOV H,A ;HL = END OF BUFF
MOV A,L
SUB C
MOV L,A
MOV A,H
SBB B
MOV H,A ;HL = DATA POINTER
MOV A,M ;GET BYTE
XCHG ;EFCB BACK TO HL
CPI 1AH ;EOF?
RZ ;YES, LEAVE POINTERS
DCX B ;DECR COUNT
DCX H ;"BYTES LEFT"
MOV M,B
DCX H
MOV M,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 MOV E,M
INX H
MOV D,M ;DE=BUF ADDR
INX H
MOV C,M
INX H
MOV B,M ;BC=BYTES IN BUFF
PUSH D ;SAVE FCB
XCHG
DAD B ;TO NEXT BYTE
MOV M,A ;STORE IT
INX B ;ONE MORE
XCHG
POP D
;
;SEE IF BUFFER IS FULL
;
INX H ;GET
MOV A,M ; SIZE
CMP B ;FULL?
JNZ WRBNOWR ;NO WRITE
;
ADD A ;MULTIPLY BY 2
MOV B,A ;SECTOR COUNT IN B
INX H ;TO FCB
PUSH H ;SAVE FCB POINTER
MOV A,M ;GET..
INX H ;..FCB..
MOV H,M ;..ADDR..
MOV L,A ;..TO HL
;
WRBLP PUSH D ;SAVE DMA ADDR
PUSH H ;SAVE FCB ADDR
PUSH B
PUSH D
PUSH H
MVI C,STDMA
CALL BDOS ;SET DMA ADDR
POP H
POP D
POP B
POP D ;GET FCB
PUSH B
PUSH D
PUSH H
MVI C,WRITE
CALL BDOS
POP H
POP D
POP B
ORA A
POP H ;HL=DMA, DE=FCB
JNZ WRBERR ;GOT ERR
MOV A,L
ADI 80H ;TO NEXT BUFF
MOV L,A
MOV A,H
ACI 0
MOV H,A
XCHG ;DMA TO DE, FCB TO HL
DCR B ;MORE SECTORS?
JNZ WRBLP ;YES, MORE
;
WRBRET POP H ;GET FCB POINTER
DCX H ;TO LENGTH
DCX H ;TO COUNT
MVI M,0 ;SET 0 TO WRITE
DCX H ;TO LO COUNT
MVI M,0
PUSH B
PUSH D
PUSH H
MVI C,STDMA
LXI D,80H+BIAS
CALL BDOS
POP H
POP D
POP B
RET
;
WRBNOWR DCX H ;TO LENGTH
MOV M,B ;SET NEW LENGTH
DCX H
MOV M,C
RET
;
;FLUSH THE EFCB BUFFERS
;
FLUSH MOV E,M
INX H
MOV D,M ;DE=BUF ADDR
INX H
MOV C,M
INX H
MOV B,M ;BC=BYTES IN BUFF
INX H ;TO COUNT
MOV A,B
ORA C
RZ ;NOTHING TO WRITE
MOV A,C ;GET LOW COUNT
ADD A ;SHIFT HIGH TO CARRY
MOV A,B ;GET LOW COUNTAL
RAL ;MULT BY 2, + CARRY
INR A ;FUDGE FOR PARTIAL SECT
MOV B,A ;SAVE SECTOR COUNT
INX H ;TO FCB
MOV A,M
INX H
MOV H,M
MOV L,A ;HL=FCB
;
FLUSHL PUSH B
PUSH D
PUSH H
MVI C,STDMA
CALL BDOS
POP H
POP D
POP B
XCHG
PUSH B
PUSH D
PUSH H
MVI C,WRITE
CALL BDOS
POP H
POP D
POP B
XCHG
ORA A
JNZ WRBERR
PUSH H
LXI H,80H
DAD D
XCHG
POP H
DCR B
JNZ FLUSHL
XCHG
PUSH B
PUSH D
PUSH H
MVI C,CLOSE
CALL BDOS
POP H
POP D
POP B
INR A
RNZ
CALL ERXIT
DB '++OUTPUT FILE CLOSE ERROR ++$'
;
WRBERR CALL ERXIT
DB '++OUTPUT FILE WRITE ERROR++$'
;
;EXIT WITH ERROR MESSAGE
;
MSGEXIT EQU $ ;EXIT W/"INFORMATIONAL" MSG
;
ERXIT POP D ;GET MSG
MVI C,PRINT
CALL BDOS
;
;EXIT, RESTORING STACK AND RETURN
;
EXIT JMP 0+BIAS
;
;====> START OF WORK AREA
;
EXTFCB DW DKBUF
DW 0
DB 4
DW FCB
PREV DW PTR ;POINTER TO PREV POINTER
SKIPC DB 0 ;SKIP CHARS END
DS 8 ;VARIABLE SKIP CHARS
;
DS 100 ;STACK AREA
STACK EQU $
;
OUTNAME DS 12 ;OUTPUT FILENAME
SWAPS DS 1
CURR DS 2
PTR DS 2 ;POINTER TO FIRST NAME
;
ORG ($+255) AND 0FF00H ;TO PAGE
;
DKBUF DS 256*4 ;4 PAGES OF BUFFER
SBUFF DS 0 ;NAMES READ IN HERE
;
END