home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol017
/
sortv-12.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
13KB
|
767 lines
; SORTV.ASM ver 1.2
; by Ward Christensen
; (revised 1/3/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.
;
;--->NEEDS MAC TO ASSEMBLE<---
;
;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.
;
;EX: 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
;
;(FROM EQU10.LIB...)
;
MF SET 0 ;SHOW MOVE NOT REQUESTED
CF SET 0 ;SHOW COMP NOT REQUESTED
;
;DEFINE SOME MACROS TO MAKE THINGS EASIER
;
;DEFINE DATA MOVE MACRO: MOVE from,to,length
; from may be addr, or quoted string
;
MOVE MACRO ?F,?T,?L
MCSUB ?F,?T,?L ;;HANDLE ARGS
CALL MOVER
MF SET -1 ;;SHOW EXPANSION
ENDM
;
;COMPARE MACRO
COMP MACRO ?F,?T,?L
MCSUB ?F,?T,?L ;;HANDLE ARGS
CALL COMPR
CF SET -1 ;;SHOW EXPANSION
ENDM
;
;MCSUB - HANDLES MOVE, COMPARE ARGUMENTS
MCSUB MACRO ?F,?T,?L
IF NOT NUL ?F
IRPC ?C,?F
?Q SET '&?C&?C' ;;TEST FOR QUOTE
EXITM
ENDM
IF ?Q EQ ''''
LOCAL ?B,?Z
CALL ?Z
?B DB ?F
?Z POP H ;GET FROM
LXI B,?Z-?B ;GET LEN
ELSE
LXI H,?F
ENDIF
ENDIF
IF NOT NUL ?T
LXI D,?T
ENDIF
IF NOT NUL ?L
LXI B,?L
ENDIF
ENDM
;
;DEFINE CP/M MACRO - CPM FNC,PARM [,NOSAVE]
;
CPM MACRO ?F,?P,?N
IF NUL ?N
PUSH B
PUSH D
PUSH H
ENDIF
IF NOT NUL ?F
MVI C,?F
ENDIF
IF NOT NUL ?P
LXI D,?P
ENDIF
CALL BDOS
IF NUL ?N
POP H
POP D
POP B
ENDIF
ENDM
;
RDB MACRO ?F
PUSH D
PUSH H
LXI H,?F
CALL RDBYTE
POP H
POP D
ENDM
;
WRB MACRO ?F
PUSH H
LXI H,?F
CALL WRBYTE
POP H
ENDM
;
EFCB MACRO ?B,?P,?F
DW ?B
DW 0
DB ?P
DW ?F
ENDM
;
ORG 100H
;
;INIT LOCAL STACK
;
LXI SP,STACK
;
CALL START
DB 'SORTV rev 1.2'
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
;
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
MOVE FCB2,OUTNAME,12
RET
;
;OUTPUT NAME = INPUT NAME
;
SAMENAM MOVE FCB,OUTNAME,12
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 CPM OPEN,FCB
INR A
RNZ ;SUCCESSFUL? RETURN
CALL ERXIT
DB '++Input file not found$'
;
;====> READ IN THE NAMES
;
READN LXI H,BUFF ;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?
RDB EXTFCB ;READ A BYTE
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.
RDB EXTFCB ;GOBBLE UP LF
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
CPM WRCON
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 NECESS
;
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 ENTRY, 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
MOVE OUTNAME,FCB,12 ;RESTORE NAME
CPM ERASE,FCB
CPM MAKE,FCB
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
WRB EXTFCB ; CHAR
LXI H,EXTFCB ;FLUSH
CALL FLUSH ; BUFFERS
CPM STDMA,80H ;RESET DMA
CPM CLOSE,FCB ;CLOSE,
CALL ERXIT ; AND EXIT
DB '++DONE++$'
;
WRITEL PUSH H ;SAVE POINTER
INX H
;
WRLP INX H ;TO NEXT CHAR
MOV A,M ;GET CHAR
WRB EXTFCB ;WRITE IT
MOV A,M ;SEE IF END
CPI CR ; OF LINE
JNZ WRLP ;NO, LOOP
MVI A,LF ;OTHERWISE
WRB EXTFCB ; WRITE LF
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
;
IF MF ;MACRO EXPANSION FLAG SET?
MOVER MOV A,M
STAX D
INX H
INX D
DCX B
MOV A,B
ORA C
JNZ MOVER
RET
ENDIF
;
IF CF ;MACRO EXPANSION FLAG SET?
COMPR LDAX D
CMP M
RNZ
INX D
INX H
DCX B
MOV A,B
ORA C
JNZ COMPR
RET
ENDIF
;
; 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 ;..FCB..
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
CPM STDMA ;SET DMA ADDR
POP D ;GET FCB
CPM READ
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 ;BACK TO "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 TO WRITE)
; 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
CPM STDMA ;SET DMA ADDR
POP D ;GET FCB
CPM WRITE
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
CPM STDMA,80H
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 CPM STDMA
XCHG
CPM WRITE
XCHG
ORA A
JNZ WRBERR
PUSH H
LXI H,80H
DAD D
XCHG
POP H
DCR B
JNZ FLUSHL
XCHG
CPM CLOSE
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
;
;====> START OF WORK AREA
;
EXTFCB EFCB DKBUF,4,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
BUFF EQU $ ;NAMES READ IN HERE
;
;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
FCB EQU 5CH
FCB2 EQU 6CH
FCBEXT EQU FCB+12
FCBRNO EQU FCB+32
;
END