;Array exchange sort in place in memory.
;Copyright 1979,1980,1981 by C. E. Duncan. Written 1979 June 30.
;Taken from an original program written by E. W. Dijkstra on
; the back of my business card at the international meeting
; on software reliability at Los Angeles in 1975.
;Permission granted to copy for any non-commercial use.
;Revised 17:55 1981 February 10.
;
;This program, BSORT, is called as a CP/M .COM routine as follows:
;
; BSORT
;
; where file names are "[d:]name.typ" as usual in CP/M.
; The user will be asked for record length and sort parameters
; through a console dialog.
;
PAGE 0 ;defeats CP/M page count
ORG 0100H ;program origin
BSORT:
;
;Set internal stacks
LXI H,BSTACK ;bounds stack
SHLD BSAVE
LXI H,PSTACK ;program stack
SHLD PSAVE
SPHL
;Initialize
CALL INIT1
;Save default disk
MVI C,RTCDK ;return current disk number
CALL BDOS
STA CDSKSAV
;Set default disk to input file
LDA SFDN ;input file disk number
MOV E,A
CALL ASGDSK
;Read file and check further
CALL INIT2
;Do the sort
CALL PARTIT
;Assign output disk as default
LDA DFDN
MOV E,A
CALL ASGDSK
;Write output file
CALL WRTARY
;Close output
LXI D,DFCB
MVI C,CLOSE
CALL BDOS
;Restore default disk
LDA CDSKSAV
MOV E,A
CALL ASGDSK
JMP QUIT ;return to CP/M-CCP
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * *
INIT1:
;Initialize variables, read parameters, check values.
;Revised 20:10 1981 January 26.
;
;Move output file name to output FCB.
MVI A,12 ;character count
LXI D,SFDA ;from
LXI H,DFDN ;to
CALL SMOVE
;Set current (next) record pointer to 0.
XRA A
STA SFCR ;input
STA DFCR ;output
STA DFEX ;file extent
STA ABRTF ;abort flags
STA STLV ;bounds stack level
;Check input file name
LXI D,SFCB ;input FCB
CALL CHKFN
JNC OK01
LXI H,ABRTF ;set abort flag
INR M
LXI D,FNIMSG
CALL PUTMSG
OK01:
; Check output file name
LXI D,DFCB ;output FCB
CALL CHKFN
JNC OK02
LXI H,ABRTF ;set abort flag
INR M
LXI D,FNOMSG
CALL PUTMSG
;
OK02:
;Abort if these names do not check
LDA ABRTF
ORA A
JNZ ABORT
; Calculate storage available
LXI H,AR ;array base address
SHLD ARBASE
XCHG ;to DE
LHLD BDOS+1 ;BDOS base
CALL DIFF2 ;subtract
DCR H ;make room for temporary storage
SHLD MARSIZ ;available memory
; Check size of input file
MVI A,03FH ; "?" to insure match of
STA SFEX ; all extents
LXI H,0 ; Reset sector count
SHLD FSCNT
LXI D,SBUF ; Prepare a buffer for
MVI C,STDMAAD ; directory information
CALL BDOS
MVI C,SRCHFST ; Bring in directory for first
LXI D,SFCB ; extent. Returns 0,1,2 or 3
CALL BDOS ; in 2.2, 0-3F in 1.4
CPI 0FFH
JNZ OK03
LXI D,FNPMSG ; not found so quit
CALL PUTMSG
JMP ABORT
OK03:
ANI 3 ; MOD 4 (needed by CP/M 1.4 only)
;Address directory entry (one of four in buffer), then
; get sector count. 32 bytes per entry.
ADD A ; *2
ADD A ; *4
ADD A ; *8
ADD A ; *16
ADD A ; *32
MVI D,15 ; plus offset to count byte
ADD D
MOV E,A ; add buffer base address
MVI D,0
LXI H,SBUF
DAD D
MOV A,M ; sector count
MOV E,A
LHLD FSCNT ; accumulate
DAD D
SHLD FSCNT
CPI 080H ; Full track?
JNZ OK04 ; no, go on
MVI C,SRCHNXT ; Get information on
LXI D,SFCB ; next extent
CALL BDOS
CPI 0FFH ; No more entries when FF hex
JNZ OK03 ; Get next entry
OK04:
XRA A ; Reset extent byte
STA SFEX ; to zero
; Deduce input file size
LHLD FSCNT ; number of sectors
MOV A,H ; check for empty
ORA L
JZ ABORT ; nothing here
;Multiply by 128 bytes per sector
DAD H ; *2
JC OK05
DAD H ; *4
JC OK05
DAD H ; *8
JC OK05
DAD H ; *16
JC OK05
DAD H ; *32
JC OK05
DAD H ; *64
JC OK05
DAD H ; *128
JNC OK06
OK05:
LXI D,MULMSG ; multiply error
CALL PUTMSG
JMP ABORT
OK06:
; Last sector may have less than 128 bytes, will check later
SHLD BYIF
; Check that there is enough memory
XCHG
LHLD MARSIZ ;memory available
CALL DIFF2
ORA A
JP OK07
LXI D,FSZMSG ; report file larger than memory
CALL PUTMSG
JMP ABORT
OK07:
;Calculate address of temporary record storage area
LHLD BYIF
LXI D,AR
DAD D
SHLD AWTP
; Open input file
MVI C,OPEN
LXI D,SFCB
CALL BDOS
INR A
JNZ OK08
LXI D,FNPMSG ; file not present
CALL PUTMSG
JMP ABORT
;Open output file
OK08:
MVI C,DELETE ;delete file of same name
LXI D,DFCB
CALL BDOS
MVI C,CREATE ;make new file
LXI D,DFCB
CALL BDOS
INR A
JNZ OK09
LXI D,NDSMSG ; signal no directory space
CALL PUTMSG
JMP ABORT
OK09:
; Ask for record length
LXI D,RCLMSG
CALL PUTMSG
CALL READCON ;read console input
LXI D,CONSIZ ;string response
LXI B,AR ;temporary buffer
CALL SCANBR ;extract number
JC OK09 ;try again
LDAX B ;count
INX B ;1st character
CALL ROW1NBR ;convert to binary
JC OK09 ;trouble
MOV A,L
STA RLEN
; calculate twos complement
CMA
INR A
STA MRLEN
OK10:
; Ask for sort parameters.
XRA A ; reset parameter count
STA NBRFND
LXI D,PARMSG
CALL PUTMSG
CALL READCON ;read console input
LDA CONSIZ ;number of characters read
ORA A
JZ OK10 ;no input, try again
CALL RDPARM ;read, convert and store sort parms
JC OK10 ;try again
CALL CKPARM ;check parameters
JC OK10 ;ask again
RET ;end of INIT1
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * *
;
INIT2:
;Read input file to array, correct file size, final checks.
;Written by C. E. Duncan 1979 June 30.
;Revised 08:15 1981 February 4.
; Read input file to array
CALL RDARRAY
; Check and possibly correct file size calculation BYIF
; HL points to byte after last sector read.
LDA SFS1 ; bytes remain in last sector
ORA A
JNZ OK12
MVI A,01AH ; must remove eof (1A) bytes
LXI B,0 ; clear counter
OK11:
DCX H ; char in file
CMP M ; is it EOF?
JNZ OK13 ; no
INX B ; count
JMP OK11
OK12:
CMA ; subtract off eofs
MOV C,A
MVI B,0FFH ; minus sign
JMP OK14
OK13:
MOV A,B ; get twos complement
CMA ; to subtract
MOV B,A
MOV A,C
CMA ; subtract off unused bytes
MOV C,A
OK14:
INX B ; twos complement
LHLD BYIF
DAD B ; subtract
SHLD BYIF
; Check that file size is multiple of record length
; and calculate upper and lower bounds
MOV A,H ; check that there is a record
ORA L
JZ ABORT ; nothing here
LDA RLEN
CALL DIV12
JNC OK15
LXI D,DIVMSG
CALL PUTMSG
JMP ABORT
OK15:
MOV A,L ; check remainder
CMP H
JZ OK16
LXI D,RLMSG ;abort msg
CALL PUTMSG
JMP ABORT
OK16:
MOV H,B ; store quotient
MOV L,C ; as UPB
SHLD AUPB
SHLD CUPB
LXI H,1 ; LWB = 1
SHLD ALWB
SHLD CLWB
;Initialize array index calculation
; A[I] has address = ARRAY BASE - (LWB A)*RLEN + I*RLEN
; = ARIF + I*RLEN
;
LHLD ALWB ;LWB of A
XCHG ; to DE
LDA RLEN
CALL MUL12
JC ABORT ;overflow
XCHG
LHLD ARBASE ; calculate HL - DE
CALL DIFF2
ORA A ; check sign
JP OK17 ; positive, ok
MOV A,H ; complement if negative
CMA
MOV H,A
MOV A,L
CMA
MOV L,A
INX H
OK17:
SHLD ARIF
;Addresses of sort strings in temporary area
LHLD AWTP ; temporary record store
LDA POOF1 ; 1st sort offset
MVI B,0
MOV C,A
DAD B
SHLD KWTP1 ; address of awtp[m:n]
LDA PARM3 ; is there a 2nd sort?
ORA A
RZ
LDA POOF2 ; 2nd sort offset
MOV C,A
LHLD AWTP
DAD B
SHLD KWTP2 ; address of awtp[u:v]
RET
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * *
;
PARTIT:
;Partition sort based on a program by Dijkstra.
;Written by C. E. Duncan 1979 June 30.
;Revised 17:30 1981 February 8.
;
; p = LWB a, q = UPB a
;
;Algorithm: partition and sort until q < p
; WHILE p <= q
; DO
; IF q = p
; THEN
; unstack
; ELSE
; IF q - p <= slim
; THEN
; shorts {insertion sort}
; ELSE
; parta {partition left}
; {makes two partitions: a[p] to a[s] and a[r] to a[q]}
; FI
; FI;
; IF s = p
; THEN
; p := r
; ELSE
; IF s < p
; THEN
; partb {partition right}
; {required if parta has no "small" element}
; ELSE
; IF q = r
; THEN
; q := s
; ELSE
; IF q < r
; THEN
; unstack
; ELSE
; IF q - r > s - p
; THEN
; stack right;
; q := s
; ELSE
; stack left;
; p := r
; FI
; FI
; FI
; FI
; FI
; OD
;
LHLD CLWB ; P = LWB current partition
XCHG
LHLD CUPB ; Q = UPB current partition
CALL DIFF2 ; compare
ORA A
RM ;sort complete when Q < P
JZ UNSTACK ; only one element
XCHG
LXI H,SLIM ;low size limit
CALL DIFF2 ;SLIM - (P - Q)
ORA A
PUSH PSW
CP SHORTS ;use insertion sort, small partition
POP PSW
JP UNSTACK ;this partition completed
CM PARTA ;partition leftward
; Check size of lower partition
STAR01:
LHLD CLWB ; P = LWB left
XCHG
LHLD PS ; S = UPB left
CALL DIFF2 ; S - P
ORA A
JZ STAR02 ; only one element, finished
JM STAR04 ; no small element
SHLD SMP
; Upper partition.
LHLD PR ; R = LWB right
XCHG
LHLD CUPB ; Q = UPB right
CALL DIFF2 ; Q - R
ORA A
JZ STAR03 ; only one element, finished
JM UNSTACK ; finished with this partition
; because no large element after
; having no small element.
SHLD QMR
; Save bounds of larger partition.
; If Q - R > S - P then upper part is larger.
LXI H,0 ; save program stack
DAD SP
SHLD PSAVE
LHLD BSAVE ; retrieve bounds stack
SPHL
;
LHLD QMR ; Q - R
XCHG
LHLD SMP ; S - P
CALL DIFF2 ; (S-P) - (Q-R)
ORA A
JM STHI ; stack bunds for high side
STLO:
LHLD CLWB ; P, new lower bound
PUSH H
LHLD NUBL ; S, new upper bound
PUSH H
LHLD NLBH ; R, set new LWB for high side
SHLD CLWB
JMP REST ; restore program stack
STHI:
LHLD NLBH ; R, new lower bound
PUSH H
LHLD CUPB ; Q, new upper bound
PUSH H
LHLD NUBL ; S, new upper bouond for low side
SHLD CUPB
REST:
LXI H,0 ; restore program stack
DAD SP
SHLD BSAVE
LHLD PSAVE
SPHL
LXI H,STLV ; increment stack level
INR M
JMP PARTIT ; process next partition
;
; Process upper part
STAR02:
LHLD PR ; R is new lower bound
SHLD CLWB ;
JMP PARTIT ;
STAR03:
; Process lower part
LHLD PS ; S is new upper bound
SHLD CUPB ;
JMP PARTIT ;
STAR04:
; Partition again, using R <= T and S > T in place of
; R < T and S >= T respectively.
CALL PARTB ;
JMP STAR01 ;
;
UNSTACK:
; Recover bounds of next section to be partitioned
LXI H,STLV ; check level
DCR M ;
RM ; stack empty, sort completed
LXI H,0 ; save program stack
DAD SP ;
SHLD PSAVE ;
LHLD BSAVE ; get bounds stack
SPHL ;
POP H ;
SHLD CUPB ; UPB
POP H ;
SHLD CLWB ; LWB
LXI H,0 ; restore program stack
DAD SP ;
SHLD BSAVE ;
LHLD PSAVE ;
SPHL ;
JMP PARTIT ; return, do next section
;
PARTA:
;Re-arrange array AR into two partitions the left of which contains
; elements which precede a pivot element, and the right contains
; those which do not.
;Written by C. E. Duncan 1979 June 30.
;Revised 15:06 1981 January 31.
;
; R = LWB A, S = UPB A, T = (R+S) OVER 2.
;
;Algorithm:
; WHILE LWB A <= R < S <= UPB A
; DO
; SWAP A[R] and A[S];
; WHILE A[R] precedes A[T]
; DO
; R +:= 1
; OD;
; WHILE A[S] does not precede A[T]
; DO
; S -:= 1
; OD
; OD
;
;Calculate addresses
LDA POOF1 ; 1st sort parameter offset
MVI B,0
MOV C,A
LHLD CLWB ; current LWB
SHLD PR ; R
XCHG
CALL INDXR ; calculate address
SHLD ACR ; .A[R]
DAD B
SHLD AQR1 ; .A[R][M:N], 1st sort string
LHLD CUPB ; current LWB
SHLD PS ; S
XCHG
CALL INDXR
SHLD ACS ; .A[S]
DAD B
SHLD AQS1 ; .A[S][M:N]
LHLD PR ; R
XCHG
LHLD PS ; S
DAD D ; R + S
CALL SHRHL ; divide by 2
XCHG
CALL INDXR ; .A[T]
XCHG ; move A[T], the pivot element, to
LHLD AWTP ; a safe place
LDA RLEN
CALL SMOVE
; Take care of possible 2nd sort substring
LDA PARM3
ORA A
JZ PAR01 ;not needed
LDA POOF2 ;2nd ss offset
MVI B,0
MOV C,A
LHLD ACR ; .A[R]
DAD B
SHLD AQR2 ; .A[R][V:W]
LHLD ACS
DAD B
SHLD AQS2 ; .A[S][V:W]
PAR01:
;Check if finished
LHLD PS ; S
XCHG
LHLD PR ; R
CALL DIFF2 ; R - S
ORA A
JP PAR03 ; finished
; Update addresses of A[R] and A[S]
LHLD PR ; R
XCHG
CALL INDXR
SHLD ACR ; .A[R]
LHLD PS ; S
XCHG
CALL INDXR
SHLD ACS ; .A[S]
; Swap
LDA RLEN
LHLD ACR ; .A[R]
XCHG
LHLD ACS ; .A[S]
CALL SWAP
; While A[R] precedes A[T], etc.
LHLD AQR1 ; .A[R][M:N]
XCHG
PAR01A:
LDA SPL1 ;1st sort length
LHLD KWTP1 ; .A[T][M:N]
XCHG
CALL CMPSRW
ORA A
JZ PAR04 ; check 2nd sort substring
PAR01B:
PUSH PSW
LDA SSEQ1 ; check direction
ORA A
JZ PAR01C ; ascending
POP PSW ; descending
JZ PAR02
JP PAR01D ; A[R] precedes A[T], down
JMP PAR02
PAR01C:
POP PSW
JP PAR02 ; A[R] does not precede A[T], up
PAR01D:
LHLD PR ; increment R
INX H
SHLD PR
LDA RLEN
MVI B,0
MOV C,A
LDA PARM3 ;2nd sort?
ORA A
JZ PAR01E ;no
LHLD AQR2 ;update .A[R][V:W], 2nd sort string
DAD B
SHLD AQR2
PAR01E:
LHLD AQR1 ;update .A[R][M:N] 1st sort
DAD B
SHLD AQR1
XCHG
JMP PAR01A
PAR02:
; While A[S] does not precede A[T] etc.
LHLD AQS1 ; .A[S][M:N]
XCHG
PAR02A:
LDA SPL1 ; length of 1st sort
LHLD KWTP1 ; 1st sort string address
XCHG
CALL CMPSRW
ORA A
JZ PAR05 ; check 2nd sort
PAR02B:
PUSH PSW
LDA SSEQ1 ; check direction
ORA A
JZ PAR02C ; ascending
POP PSW
JM PAR02D
JZ PAR02D
JMP PAR01 ; S precedes T
PAR02C:
POP PSW
JM PAR01
PAR02D:
LHLD PS ; decrement S
DCX H
SHLD PS
; Check array bound at lower limit, S < LWB
XCHG
LHLD CLWB ; P = LWB A
XCHG
CALL DIFF2 ; S - P
ORA A
JM PAR03 ; no small element
;Update addresses for next comparison
LDA MRLEN ; minus RLEN
MVI B,0FFH
MOV C,A
LDA PARM3 ;check for 2nd sort
ORA A
JZ PAR02E ;no
LHLD AQS2
DAD B
SHLD AQS2
PAR02E:
LHLD AQS1
DAD B ; reduce address by RLEN
SHLD AQS1
XCHG
JMP PAR02A
PAR03:
LHLD PR
SHLD NLBH ; new LWB for right partition
LHLD PS
SHLD NUBL ; new UPB for left partition
RET
PAR04:
LDA PARM3
ORA A
JZ PAR01B ;no 2nd sort
LHLD KWTP2
XCHG
LHLD AQR2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JZ PAR04A ; ascending
POP PSW
JZ PAR02
JP PAR01D
JMP PAR02
PAR04A:
POP PSW
JM PAR01D
JMP PAR02 ; this one is out of order
;
PAR05:
LDA PARM3 ; is there a 2nd sort?
ORA A
JZ PAR02B ; no
LHLD KWTP2
XCHG
LHLD AQS2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JZ PAR05A
POP PSW
JZ PAR02D
JM PAR02D
JMP PAR01
PAR05A:
POP PSW
JP PAR02D
JMP PAR01
;
PARTB:
;Re-arrange array A into two partitions, the right of which contains
; elements which follow a pivot element, and the left contains those
; which do not.
;Written by C. E. Duncan 1979 June 30.
;Revised 18:50 1981 February 8.
;
; R = LWB A, S = UPB A, T = (R+S) OVER 2
;
;Algorithm:
; WHILE LWB A <= R < S <= UPB A
; DO
; SWAP A[R] and A[S];
; WHILE A[R] does not follow A[T]
; DO
; R +:= 1
; OD;
; WHILE A[S] follows A[T]
; DO
; S -:= 1
; OD
; OD
;
; Calculate addresses
LDA POOF1 ; 1st sort offset
MVI B,0
MOV C,A
LHLD CLWB ; current LWB A
SHLD PR ; R
XCHG
CALL INDXR
SHLD ACR ; .A[R]
DAD B ; .A[R][M:N]
SHLD AQR1
LHLD CUPB
SHLD PS ; S
XCHG
CALL INDXR
SHLD ACS ; .A[S]
DAD B
SHLD AQS1 ; .A[S][M:N]
LHLD PR ; R
XCHG
LHLD PS ; S
DAD D ; R+S
CALL SHRHL ; shift right, OVER 2
XCHG
CALL INDXR ; address of A[T]
XCHG ; move A[T] to a safe place
LHLD AWTP
LDA RLEN
CALL SMOVE
; Take care of 2nd sort substring
LDA PARM3 ; is there one?
ORA A
JZ PAB01 ; no
LDA POOF2 ; offset
MVI B,0
MOV C,A
LHLD ACR
DAD B
SHLD AQR2 ; .A[R][V:W]
LHLD ACS
DAD B
SHLD AQS2 ; .A[S][V:W]
PAB01:
; Check completion
LHLD PS ; S
XCHG
LHLD PR ; R
CALL DIFF2 ; R-S
ORA A
JP PAB03 ; finished
; Update addresses of A[R] and A[S]
LHLD PR ; R
XCHG
CALL INDXR
SHLD ACR ; .A[R]
LHLD PS ; S
XCHG
CALL INDXR
SHLD ACS ; .A[S]
; Swap Elements with indices R and S
LDA RLEN
LHLD ACR ; .A[R]
XCHG
LHLD ACS ; .A[S]
CALL SWAP
; While A[R] does not follow A[T] increment R.
LHLD AQR1 ; .A[R][M:M]
XCHG
PAB01A:
LDA SPL1 ; length sort 1
LHLD KWTP1 ; .A[T][M:N]
CALL CMPSRW
ORA A
JZ PAB04 ; check 2nd sort
PAB01B:
PUSH PSW
LDA SSEQ1 ; direction
ORA A
JZ PAB01C
POP PSW ; descending
JM PAB01D
JZ PAB01D
JMP PAB02
PAB01C:
POP PSW
JM PAB02
PAB01D:
LHLD PR ; R
INX H
SHLD PR
; Check upper bound in case no large element
XCHG
LHLD CUPB ; Q = UPB A
CALL DIFF2
ORA A
JM PAB03 ; upper limit, no large element
; Update addresses, etc.
LDA RLEN
MVI B,0
MOV C,A
LDA PARM3
ORA A ; 2nd sort
JZ PAB01E ; no
LHLD AQR2 ; .A[R][V:W]
DAD B
SHLD AQR2
PAB01E:
LHLD AQR1
DAD B
SHLD AQR1
XCHG
JMP PAB01A
PAB02:
;While A[S] follows A[T] decrease S, etc.
LHLD AQS1 ; .A[S][M:N]
XCHG
PAB02A:
LDA SPL1
LHLD KWTP1
CALL CMPSRW
ORA A
JZ PAB05 ; check for 2nd sort
PAB02B:
PUSH PSW
LDA SSEQ1
ORA A
JZ PAB02C
POP PSW
JZ PAB01
JP PAB02D
JMP PAB01 ; A[S] <= A[T]
PAB02C:
POP PSW
JP PAB01
PAB02D:
LHLD PS ; decrement S
DCX H
SHLD PS
LDA MRLEN
MVI B,0FFH
MOV C,A
LDA PARM3 ; 2nd sort?
ORA A
JZ PAB02E ; no
LHLD AQS2
DAD B
SHLD AQS2
PAB02E:
LHLD AQS1
DAD B
SHLD AQS1
XCHG
JMP PAB02A
;
PAB03:
LHLD PR
SHLD NLBH ; new LWB for right partition
LHLD PS
SHLD NUBL ; new UPB for left partition
RET
PAB04:
LDA PARM3 ; 2nd sort?
ORA A
JZ PAB01B ; no
LHLD AQR2
XCHG
LHLD KWTP2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JZ PAB04A
POP PSW
JM PAB01D
JZ PAB01D
JMP PAB02
PAB04A:
POP PSW
JP PAB01D
JMP PAB02
;
PAB05:
LDA PARM3
ORA A
JZ PAB02B
LHLD AQS2
XCHG
LHLD KWTP2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JZ PAB05A
POP PSW
JZ PAB01
JP PAB02D
JMP PAB01
PAB05A:
POP PSW
JM PAB02D
JMP PAB01
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
SHORTS:
;Insertion sort for small partitions.
;Written by C. E. Duncan 1980 February 16, from Knuth volume 3
; (Searching and Sorting) page 81.
;Revised 12:30 1981 February 8.
;
;Algorithm:
;
; FOR j FROM 2 TO UPB(a)
; DO
; IF a[j] < a[j - 1]
; THEN
; awtp := a[j];
; FOR i FROM j - 1 BY -1 TO LWB(a)
; WHILE at < a[i]
; DO
; a[i + 1] := a[i];
; k := i
; OD;
; a[k] := awtp
; FI
; OD
;
;Initialize indices and addresses.
LHLD CLWB ;LWB of current partition
SHLD PS ; j
XCHG
CALL INDXR
SHLD ACS ; address of a[j] = a[LWB]
LDA POOF1 ;1st sort offset
MVI B,0
MOV C,A
DAD B
SHLD AQS1 ;address of a[LWB][m:n]
LDA PARM3
ORA A
JZ SH01
LDA POOF2 ;2nd sort offset
MOV C,A
LHLD ACS
DAD B
SHLD AQS2 ;address of a[LWB][u:v]
SH01:
;Increment j, compare to UPB, set i := j - 1
LHLD PS ; j - 1
SHLD PR ; i := j - 1
INX H ; j +:= 1
SHLD PS ; j
;Check that j <= UPB
XCHG
LHLD CUPB ; UPB of parttion
CALL DIFF2 ;UPB - j
ORA A
RM ;finished when J > UPB
;Update addresses
LHLD ACS ;old .a[j]
SHLD ACR ;new .a[i]
LDA RLEN
MVI B,0
MOV C,A
DAD B
SHLD ACS ; new a[j]
;Update sort string addresses
LHLD AQS1
SHLD AQR1 ; a[i][m:n]
DAD B
SHLD AQS1 ; a[j][m:n]
LDA PARM3
ORA A
JZ SH02
LHLD AQS2
SHLD AQR2 ; a[i][u:v]
DAD B
SHLD AQS2 ; a[j][u:v]
SH02:
;Compare a[j] with a[j - 1] = a[i]
LHLD AQR1
XCHG
LHLD AQS1
LDA SPL1
CALL CMPSRW
ORA A
JZ SH05 ; check 2nd sort
SH03:
PUSH PSW
LDA SSEQ1 ; check direction
ORA A
JNZ SH04
POP PSW
JM SH07 ; have to do some moves
JMP SH01 ; ok where it is, go to next j
SH04:
POP PSW
JM SH01 ; ok as is
JZ SH01 ; ditto
JMP SH07
SH05:
;Second compare for a[j] and a[j - 1]
LDA PARM3
ORA A
JZ SH03 ; no 2nd compare
LHLD AQR2
XCHG
LHLD AQS2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JNZ SH06
POP PSW
JM SH07
JMP SH01
SH06:
POP PSW
JM SH01
JZ SH01
JMP SH07
;
SH07:
;Move a[j] to a safe place: awtp := a[j]
LHLD ACS
XCHG ; from
LHLD AWTP ; to
LDA RLEN
CALL SMOVE
SH08:
;Move a[i] up one place to position i + 1
LDA RLEN
MVI B,0
MOV C,A
LHLD ACR ; a[i]
MOV D,H ; to DE, from
MOV E,L
DAD B ; a[i + 1]
CALL SMOVE
;Decrement i, check against LWB
LHLD CLWB ; LWB
XCHG
LHLD PR ; i
DCX H ; i -:= 1
SHLD PR
CALL DIFF2 ; i - LWB
ORA A
JM SH14 ; at LWB, hence a[LWB] := awtp
;Decrement addresses and compare again
LDA MRLEN ; negative record length
MVI B,0FFH
MOV C,A
LHLD ACR
DAD B
SHLD ACR ; new address of a[i]
LHLD AQR1
DAD B
SHLD AQR1 ; new 1st sort address
LDA PARM3
ORA A
JZ SH09
LHLD AQR2
DAD B
SHLD AQR2 ; new 2nd sort address
SH09:
;Compare awtp = a[j] with a[i]
LHLD AQR1
XCHG
LHLD KWTP1
LDA SPL1
CALL CMPSRW
ORA A
JZ SH12
SH10:
PUSH PSW
LDA SSEQ1
ORA A
JNZ SH11
POP PSW
JM SH08 ; keep trying and comparing
JMP SH15 ; found place for at in a[i + 1]
SH11:
POP PSW
JM SH15
JZ SH15
JMP SH08
;
SH12:
;Second compare for awtp = a[j] and a[i]
LDA PARM3
ORA A
JZ SH10
LHLD AQR2
XCHG
LHLD KWTP2
LDA SPL2
CALL CMPSRW
ORA A
PUSH PSW
LDA SSEQ2
ORA A
JNZ SH13
POP PSW
JM SH08
JMP SH15
SH13:
POP PSW
JM SH15
JZ SH15
JMP SH08
;
SH14:
;Move awtp = a[j] into slot at a[LWB]
LHLD AWTP
XCHG
LDA RLEN
LHLD ACR
CALL SMOVE
JMP SH01
SH15:
;Move awtp = a[j] into slot at a[i + 1]
LHLD AWTP
XCHG
LDA RLEN
MVI B,0
MOV C,A
LHLD ACR
DAD B
CALL SMOVE
JMP SH01
;
;* * * * * * * * * * * * * * * * * * * * * *
;
ABORT:
;Return to CP/M
LXI D,ABMSG
CALL PUTMSG
JMP QUIT
;
ASGDSK:
;Assign default disk for faster input and output.
; Must have desired disk number in E, and default disk number
; in location CDSKSAV.
;Written by C. E. Duncan 1981 January 28.
XRA A ;get zero
CMP E
JNZ ASGD1
LDA CDSKSAV ;need default disk
MOV E,A
JMP ASGD2
ASGD1:
DCR E ;A-P = 1-16 become 0-15
ASGD2:
MVI C,SELDK ;select disk
CALL BDOS
RET
;
CHAROW:
;Reset carry if character in C is present in row of character
; whose address is in DE, length in B, else set carry.
; Return position number in B.
;Written by C. E. Duncan 1981 January 23.
;Revised 09:00 1981 January 28.
MOV A,B ;row length
CPI 0 ;check zero length
JZ CHAR2
XCHG ;row address in HL
MOV A,C ;character sought
MVI D,0 ;position count
CHAR1:
INR D ;count
CMP M ;is this it?
JZ CHAR3 ;yes
DCR B ;count off row
INX H ;next permitted
JNZ CHAR1 ;more
CHAR2:
STC ;signal not found
RET
CHAR3:
MOV B,D ;position number
ORA A ;found, reset carry
RET
;
CHKFN:
; Check file name for legal characters, FCB address in DE.
; Written by C. E. Duncan 1980 February 7.
; Revised 05:30 1981 February 4.
LDAX D ;drive
CPI 5 ;no more than 4 drives
JNC CHKFN2 ;out of limits
MVI B,11 ; Number of characters to check
INX D ;first character
LDAX D ; must be non-blank
CPI 021H ;
JC CHKFN2 ; not acceptable
JMP CHKFN3 ;
CHKFN1: ;
INX D ; next character
LDAX D ;
CPI 020H ; blank
JC CHKFN2 ; control character
CHKFN3:
CPI 05BH ; [
JNC CHKFN2 ; also unacceptable
DCR B ; count
JNZ CHKFN1 ; return for next
XRA A ; signal ok
RET ;
CHKFN2: ;
STC ; signal presence of
RET ; unacceptable character
;
CKPARM:
;Check sort parameters. Each parameter one byte from PARM1.
;Written by C. E. Duncan 1981 January 21.
;Revised 13:37 1981 January 28.
;
;get parameters in registers
LXI H,PARM1 ;address parameters
MOV B,M
INX H
MOV C,M
INX H
MOV D,M
INX H
MOV E,M
LDA RLEN
MOV H,A
;check parameters <= RLEN
MOV L,B
CALL KPR ;check range of parm1
RC ;out of limits
MOV L,C
CALL KPR ;check parm2
RC
MOV A,D ;is there a 2nd sort range?
CPI 0
JZ KRR ;no
MOV L,D
CALL KPR ;check parm3
RC
MOV L,E
CALL KPR
RC
JMP KRR
KPR:
MOV A,L
CPI 1
RC ;< 1
MOV A,H
SUB L
RET ;carry set if > RLEN
KRR:
;Calculate sort string lengths and check them
MOV A,C ;1st
SUB B
RC ;negative length
INR A
STA SPL1 ;length of 1st sort substring
MOV L,A
MOV A,H ;RLEN
SUB L
RC ;substring longer than record
MOV A,B ;PARM1
DCR A
STA POOF1 ;offset of sort substring in record
MOV A,D ;PARM3
ORA A
RZ ;ok return, only one substring
;Have 2nd sort substring
MOV L,A
MOV A,E ;PARM4
SUB L
RC ;negative length
INR A
STA SPL2
MOV L,A
MOV A,H
SUB L
RC ;longer than RLEN
MOV A,D
DCR A
STA POOF2 ;offset
;Check for sort field overlap
MOV A,E ;PARM4
SUB B ;PARM1
JC KRS ;ok
MOV A,C ;PARM2
SUB D ;PARM3
JC KRS ;ok
STC ;overlap
RET
KRS:
XRA A ;ok, reset carry
RET
;
CMPSRW:
;Compare two rows of character of equal length.
;Registers DE and HL have addresses of the two rows of character,
; register A the count. Return -1, 0, +1 in register A as HL < DE,
; HL = DE, HL > DE respectively.
;Written by C. E. Duncan 1981 January 26.
MOV B,A ;count
INR B
CMPSRWA:
DCR B
JZ CMPSRWEQ ;equal
LDAX D
CMP M
JC CMPSRWGT ;HL > DE
JNZ CMPSRWLT ;HL < DE
INX D ;equal so far
INX H
JMP CMPSRWA
CMPSRWGT:
MVI A,1
RET
CMPSRWEQ:
XRA A
RET
CMPSRWLT:
MVI A,-1
RET
;
DIFF2:
;Calculate difference of integers in DE and HL. Put absolute
; difference in HL. Signal DE < HL, DE = HL, DE > HL with
; +1, 0 -1 in A.
;Written by C. E. Duncan 1980 February 18.
;Revised 13:30 1981 January 29.
MOV A,D
CMP H
JC DIF1 ; DE < HL
JNZ DIF2 ; DE > HL
MOV A,E
CMP L
JC DIF1 ; DE < HL
JNZ DIF2 ; DE > HL
LXI H,0 ; DE = HL
XRA A ; reset carry to signal equal
RET
DIF1:
MVI B,1 ; signal DE < HL
JMP DIF3
DIF2:
MVI B,0FFH ; signal DE > HL
XCHG
DIF3:
; Do subtraction
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
MOV A,B ; restore signal
STC ; set carry to signal not equal
RET
;
DIV12:
;Divide 16 bit integer in HL by eight bit SHORT INT in A;
; return 16 bit quotient in BC, remainder in HL (L).
;20:05 10 February 1980.
ORA A ;test for zero divisor
JZ DIV03 ;
PUSH A ;save divisor
CMA ;twos complement
INR A ; of divisor
MOV E,A ; to DE
MVI D,0FFH ;propagate negative sign
LXI B,0 ;clear quotient
DIV01:
DAD D ;divide by subtraction
JNC DIV02 ;
INX B ;
JMP DIV01 ;
DIV02:
POP A ;prepare
MOV E,A ; remainder
MVI D,0 ; in HL
DAD D ;
ORA A ;reset carry to
RET ; signal ok
DIV03:
STC ;signal zero
RET ; divisor
;
GETNBR:
;Extract an ASCII number (sequence of digits) from a row of character.
; Enter with row address in DE, count in BUFCNT. Return with
; DE pointing to following characters, remaining count in BUFCNT
; and extracted number converted to binary in C. Carry set if
; unsuccessful, else reset.
;Written by C. E. Duncan 1981 January 27.
;Revised 08:00 1981 January 28.
LDA BUFCNT ;get count
ORA A
JNZ GETN01
GETN00:
STC ;signal zero length in or out
RET
GETN01:
LXI B,AR-1 ;temporary store
XCHG
INR A ;count + 1
MOV D,A ; to D
MVI E,0 ;output count
DCX H
GETN02:
INX H ;next character
DCR D ;count
JZ GETN04 ;finished
MOV A,M
CPI 030H
JC GETN02 ;ignore
CPI 03AH
JNC GETN02
;Have found a digit
GETN03:
INX B ;ASCII number output
STAX B
INR E ;count output
INX H ;address of next character
DCR D ;count input
JZ GETN04 ;finished
MOV A,M
CPI 030H
JC GETN04 ;finished
CPI 03AH
JC GETN03
;Windup
GETN04:
MOV A,D
STA BUFCNT ;remaining input count
PUSH H ;save current row address
MOV A,E ;output count
LXI B,AR ;recover output address
CALL ROW1NBR ;convert ASCII number at BC to binary
POP D ;recover address
JC GETN00 ;problems
MOV C,L
RET ;binary number in C
;
INDXR:
;Get address of array element with index given in DE. Return
; address of element in HL. Array base address is stored in
; location ARBASE, RLEN, the record length is less than 256.
; Address of AR[i] is given by ARIF + I*RLEN.
; Index is checked against bounds.
PUSH D
LHLD ALWB ;check LWB
DCX H
CALL DIFF2
ORA A
JM IND02 ; LWB <= I
IND01:
LXI D,INXMSG ;report index out
CALL PUTMSG ; of bounds
JMP ABORT
IND02:
LHLD AUPB ;check UPB
POP D
PUSH D
CALL DIFF2
ORA A
JM IND01 ;abort
POP D ;index ok, I <= UPB
LDA RLEN
CALL MUL12
JC ABORT ;overflow
XCHG
LHLD ARIF
DAD D
RET
;
MU111:
;Multiply 8-bit number in E by 8-bit number in A, returning
; 8-bit number in L. Set carry for overflow, else reset.
;Written by C. E. Duncan 1981 January 24.
LXI H,0 ;zero result register
MVI D,0 ;for double add
MVI B,8 ;bit count
MU111A:
DAD H ;shift HL left
RAL ;same for multiplier
JNC MU111B
DAD D
MU111B:
DCR B ;count
JNZ MU111A ;get next bit
XRA A ;check for overflow
CMP H
RET ;carry set if H > 0
;
MUL12:
;Multiply 16-bit number in DE by 8-bit number in A, placing
; 16-bit result in HL. Carry set for overflow, else reset.
;Revised 22:22 1980 February 25.
LXI H,0 ;clear result register
MVI B,8 ;bit count
MUL12A:
DAD H ;shift left
RAL ;same for multiplier
JNC MUL12B ;this multiplier bit = 0
DAD D ;add multiplicand
RC ;carry indicates overflow
MUL12B:
DCR B ;count bits
JNZ MUL12A ;continue
ORA A ;ok, reset carry
RET
;
PUTMSG:
; Write message to console via BDOS, address in DE
PUSH D ;Save message address
LXI D,CCRLF ;CR and LF
MVI C,PCONBUF ;
CALL BDOS ;
POP D ;recover message
MVI C,PCONBUF ;Signal write to console
CALL BDOS ;
RET ;
;
RDARRAY:
;Read disk file of typed, fixed length records to array AR.
;Written by C. E. Duncan 1980 February 3.
;Revised 08:30 1981 February 4.
; Initialize
LXI B,0FF80H ; -128
LXI H,AR ; array base
DAD B ;
PUSH H ;
LXI H,0 ; Zero sector count
SHLD RSCNT ;
; Read loop
RDAL: ;
; Set DMA address
LXI B,128 ; step pointer
POP H ;
DAD B ;
PUSH H ;
XCHG ; DMA addr in DE for BDOS
MVI C,STDMAAD ;
CALL BDOS ;
; Read a sector
LXI D,SFCB ; Address FCB
MVI C,READSEQ ;
CALL BDOS ;
CPI 0 ; check successful completion
JNZ RD1 ; check further
LHLD RSCNT ; ok, count
INX H ;
SHLD RSCNT ;
JMP RDAL ; return for next sector
RD1: CPI 1 ;
JZ RD2 ; end of file
JMP ABORT ; should not happen
RD2:
; Read complete
POP H ; Restore stack
RET ;
;
RDPARM:
;Read parameters from console and store in suitable form.
;Written by C. E. Duncan 1981 January 27.
;Revised 12:20 1981 January 28.
LXI D,CONSIZ ;console buffer
LDAX D ;count
ORA A
JZ RDPFIN ;no input
STA BUFCNT ;count of unprocessed characters
INX D ;1st character
RDP1:
LDAX D ;examine character
ORI 020H ;convert to lower case
PUSH D ;save row address
MVI B,14 ;count of acceptable characters
MOV C,A ;character to be tested
LXI D,PRMCHRS ;list of ok characters
CALL CHAROW ;is it acceptable?
MOV A,C ;recover character
POP D
JNC RDP3 ;ok
RDP2:
INX D ;point to next character
LXI H,BUFCNT ;update count
DCR M
JNZ RDP1 ;keep trying
JMP RDPFIN ;no more
RDP3:
CPI 'a' ;ascending?
JZ RDP7 ;yes, no action
CPI 'd' ;descending?
JNZ RDP9 ;must be a number
LDA NBRFND ;which parameter?
CPI 2 ;is it 3rd?
JZ RDP4 ;must be 5th or 6th
CPI 4
JZ RDP5
CPI 5
JZ RDP5
JMP RDP2 ;ignore
RDP4:
LXI H,SSEQ1
JMP RDP6
RDP5:
LXI H,SSEQ2
RDP6:
INR M ;set descending
RDP7:
LXI H,NBRFND ;update parameter count
INR M
JMP RDP2 ;return for more
RDP8:
LXI H,NBRFND ;update number of parameters found
INR M
LDA BUFCNT ;check for remaining characters
ORA A
JZ RDPFIN
JMP RDP1 ;process next character
RDP9:
CALL GETNBR ;return binary in C, update buffer
LDA NBRFND ;parameter count
CPI 0
JNZ RDP10
MOV A,C
STA PARM1
JMP RDP8
RDP10:
CPI 1
JNZ RDP11
MOV A,C
STA PARM2
JMP RDP8
RDP11:
CPI 2
JNZ RDP13
RDP12:
MOV A,C
STA PARM3
JMP RDP8
RDP13:
CPI 3
JNZ RDP14
LDA PARM3
ORA A
JZ RDP12
RDP14:
MOV A,C
STA PARM4
JMP RDP8
RDPFIN:
LDA NBRFND ;all done?
CPI 2 ;at least 2
RET ;carry set if not
;
READCON:
;Read console to console buffer CONBUF.
LXI D,CONBUF
MVI C,RCONBUF
CALL BDOS
RET
;
ROW1NBR:
;Convert ASCII decimal row at (BC), length A, to 1-byte number
; in L. Set carry for overflow.
;Copyright 1980 by C. E. Duncan.
;Revised 12:20 1981 January 24.
CPI 4 ;check size
JNC RTN1A ;
CPI 0 ;
JNZ RTN1B ;
RTN1A:
STC ;signal trouble
RET ;
RTN1B:
MOV D,A ;count
MVI L,0 ;reset result register
MVI E,10 ;multiplier
RTN1C:
MOV A,L ;multiply by 10
PUSH B ;
PUSH D ;
CALL MU111 ;A * E to L
POP D ;
POP B ;
JC RTN1A ;overflow
LDAX B ;next digit
SUI 30H ;convert to binary
JM RTN1A ;not a digit
CPI 10 ;
JNC RTN1A ;not a digit
ADD L ;
MOV L,A ;
INX B ;next
DCR D ;count
JNZ RTN1C ;continue
RET ;
;
SCANBR:
;Extract an ASCII number (sequence of digits) from a string.
; Enter with address of string in DE. Leave with BC pointing
; to extracted ASCII number string, and DE pointing to remaining
; row of characters with count in A.
; String = LCCC...C.
;Written by C. E. Duncan 1981 January 23.
LDAX D ;get count
ORA A
JNZ SCNB01
SCNB00:
STC ;signal zero length in or out
RET
SCNB01:
PUSH B ;output string origin
XCHG
INR A ;count + 1
MOV D,A ; to D
MVI E,0 ;output count
SCNB02:
DCR D ;count
JZ SCNB04 ;finished
INX H ;next character
MOV A,M
CPI 030H
JC SCNB02 ;ignore
CPI 03AH
JNC SCNB02
;Have found a digit
SCNB03:
INX B ;ASCII number output
STAX B
INR E ;count output
DCR D ;count input
JZ SCNB04 ;finished
INX H ;next input character
MOV A,M
CPI 030H
JC SCNB04 ;finished
CPI 03AH
JNC SCNB04 ;finished
JMP SCNB03
;Windup
SCNB04:
POP B ;recover output origin
MOV A,E ;output count
ORA A ;test for zero length
JZ SCNB00
STAX B
MOV A,D ;input count remaining
XCHG
RET ;ok, carry reset
;
SHRHL:
;Shift HL right one bit :=: divide HL by 2.
;Written by C. E. Duncan 1979 June 30.
ANA A ;clear carry
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
RET
;
SMOVE:
;Non-overlapping move, left to right.
;Register A has count of bytes, < 256, DE address of source and
; HL address of destination.
;Written by C. E. Duncan 1980 February 18.
;Revised 17:30 1981 January 26.
MOV B,A ;count
INR B
SMOVE1:
DCR B
RZ
LDAX D
MOV M,A
INX D
INX H
JMP SMOVE1
;
SWAP:
;Exchange two rows-of-character of equal length, addresses in
; DE and HL, length in A.
;Written by C. E. Duncan 1980 February 18.
;Revised 08:40 1981 February 4.
ORA A ;check length
RZ ;finished
MOV B,A ;count
SWAP1:
MOV C,M ;save byte from HL
LDAX D ;move byte from
MOV M,A ; DE to HL
MOV A,C ;move byte from C
STAX D ; (from HL) to DE
INX D
INX H
DCR B
JNZ SWAP1
RET
;
WRTARY:
; Write array to disk file from AR.
; Written 1980 February 17.
; Revised 17:45 1981 January 28.
; Initialize
LXI B,0FF80H ; -128
LXI H,AR ; array base
DAD B ;
PUSH H ; array pointer
LHLD RSCNT ; sector count
INX H
PUSH H
LXI B,128 ;DMA address increment
WRAL:
; Check count of sectors remaining
POP D ; get count
DCX D ; count
MOV A,D
ORA E
JNZ WR1 ; more
POP H ; restore stack
RET ;finished
WR1:
; Set DMA address
POP H
LXI B,128
DAD B
PUSH H
PUSH D ; count
XCHG
MVI C,STDMAAD
CALL BDOS
; Write sector
LXI D,DFCB ; output FCB
MVI C,WRITSEQ ; sequential write
CALL BDOS
CPI 0
JZ WRAL ; ok, continue
; Abort because of disk problems
LXI H,ABRTF ; Abort flags
MOV A,M
ORI 80H
MOV M,A ; write failure
JMP ABORT ; quit
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;Patch area
PATCH DS 48
;
;Equates, literals and storage for ISORT.
;Written by C. E. Duncan 1979 June 30.
;Revised 07:25 1981 February 4.
;
;Console messages
;
CR: EQU 13 ;Carriage return
LF: EQU 10 ;Line feed
CCRLF: DB CR,LF,'$'
FNIMSG: DB 'Unacceptable character in input file name.$'
FNOMSG: DB 'Unacceptable character in output file name.$'
FNPMSG: DB 'Input file not present.$'
NDSMSG: DB 'No directory space for output file.$'
RCLMSG: DB 'Enter record length: $'
PARMSG: DB 'Enter sort parameters: $'
ABMSG: DB 'Program discontinued.$'
MULMSG: DB 'Overflow in multiply.$'
DIVMSG: DB 'Divide by zero.$'
RLMSG: DB 'File size not multiple of record length.$'
FSZMSG: DB 'File larger than available memory.$'
INXMSG: DB 'Array index out of bound.$'
;
; Storage
;
PRMCHRS: DB '0123456789ad' ;permitted parameters
;
ARBASE: DW 0 ;array base address
RLEN: DB 0 ; record length - bytes
ALWB: DW 0 ; array lower bound
AUPB: DW 0 ; array upper bound
CLWB: DW 0 ; current lower bound
CUPB: DW 0 ; current upper bound
BUFCNT: DB 0 ;characters in buffer
NBRFND: DB 0 ;parameter number
QMR: DW 0 ; Q - R
SMP: DW 0 ; S - P
PARM1: DB 0 ; sort parameters
PARM2: DB 0 ;
PARM3: DB 0 ;
PARM4: DB 0 ;
POOF1: DB 0 ;1st sort substr offset
POOF2: DB 0 ;2nd sort substr offset
SPL1: DB 0 ;1st sort substr length
SPL2: DB 0 ;2nd sort substr length
SSEQ1: DB 0 ;1st sort direction, 0=A, 1=D
SSEQ2: DB 0 ;2nd sort direction
AQR1: DW 0 ; .A[R][M:N]
AQR2: DW 0 ; .A[R][V:W]
AQS1: DW 0 ; .A[S][M:N]
AQS2: DW 0 ; .A[S][V:W]
NLBH: DW 0 ; new LWB for right partition
NUBL: DW 0 ; new UPB for left partition
ARIF: DW 0 ;Array index calculation base
MARSIZ: DW 0 ; maximum available memory
BYIF: DW 0 ; Total input file size - bytes
ABRTF: DS 1 ;Abort flags
FSCNT: DW 0 ;Sectors in input file
RSCNT: DW 0 ;Sectors read count
KWTP1: DW 0 ;Temporary storage, .AR[J][M:N]
KWTP2: DW 0 ;Temporary storage, .AR[J][V:W]
AWTP: DW 0 ; address of temp record storage
PR: DW 0 ; R
PS: DW 0 ; S
ACR: DW 0 ; .A[R]
ACS: DW 0 ; .A[S]
MRLEN: DB 0 ; negative of RLEN
CDSKSAV: DB 0 ;save default disk number
SLIM: EQU 8 ;partition size lower limit
;
DFCB: DS 36 ; output FCB
DFDN: EQU DFCB+0 ; disk name
DFEX: EQU DFCB+12 ; current extent
DFCR: EQU DFCB+32 ; current/next/record number
;
; CONSOLE BUFFER
;
CONBUF: DB CONLEN ;
CONSIZ: DS 1 ;number current characters
CONLIN: DS 254 ;character buffer
SBUF: EQU CONSIZ ;temporary buffer for disk directory
CONLEN: EQU $-CONSIZ
;
; Stack and pointers
;
BSTKDP: EQU 16*4 ;
PSTKDP: EQU 16*2 ;
DS BSTKDP ;Bounds stack
BSTACK: DW 0 ;Stack top
DS PSTKDP ; program stack
PSTACK: DW 0 ; base
STLV: DS 1 ; current stack depth
PSAVE: DW 0 ; program stack pointer
BSAVE: DW 0 ; bounds stack pointer
;
; LOGICAL I/O FUNCTION EQUATES
;
PCONBUF: EQU 9 ;print to console from buffer
RCONBUF: EQU 10 ; read console to buffer
SELDK: EQU 14 ;select disk
OPEN: EQU 15 ;open disk file
CLOSE: EQU 16 ;close disk file
SRCHFST: EQU 17 ;search first occurrence of FCB in directory
SRCHNXT: EQU 18 ;search next occurrence of FCB
DELETE: EQU 19 ;delete file
READSEQ: EQU 20 ;read next disk record
WRITSEQ: EQU 21 ;write next disk record
CREATE: EQU 22 ;create file and directory entry
RTCDK EQU 25 ;return current disk number
STDMAAD: EQU 26 ;set DMA address
;
SFCB: EQU 05CH ;Input (default) FCB
SFDN: EQU SFCB+0 ;disk number
SFEX: EQU SFCB+12 ;current extent
SFS1: EQU SFCB+13 ;bytes in last sector (maybe)
SFDA: EQU SFCB+16 ;extent allocation vector
SFCR: EQU SFCB+32 ;current/next/record number
;
QUIT: EQU 0000H ;re-boot return to CPM
BDOS: EQU 0005H ;DOS entry
; PROGRAM END
DB 'BSORT 2-2.2 PROGRAM END'
AR: DW 0 ;Base of sort array
END ;